├── lib ├── __init__.py ├── version.py ├── datatypes.py ├── logger.py ├── util.py └── annotation.py ├── client ├── dist ├── tsconfig.json ├── webpack.config.js ├── package.json ├── common.ts └── edit_mcdict.ts ├── server ├── static ├── templates │ ├── edit_mcdict.html │ └── index.html ├── __main__.py └── miogatto.py ├── .flake8 ├── static ├── vendor │ └── jquery-ui-1.12.1 │ │ ├── images │ │ ├── ui-icons_444444_256x240.png │ │ ├── ui-icons_555555_256x240.png │ │ ├── ui-icons_777620_256x240.png │ │ ├── ui-icons_777777_256x240.png │ │ ├── ui-icons_cc0000_256x240.png │ │ └── ui-icons_ffffff_256x240.png │ │ ├── LICENSE.txt │ │ ├── package.json │ │ ├── jquery-ui.theme.min.css │ │ ├── AUTHORS.txt │ │ ├── jquery-ui.structure.min.css │ │ ├── jquery-ui.theme.css │ │ └── jquery-ui.structure.css ├── edit_mcdict_style.css ├── style.css ├── edit_mcdict.js └── index.js ├── Dockerfile ├── requirements.txt ├── CONTRIBUTING.md ├── LICENSE ├── .gitignore ├── tools ├── migrate_data_02to10.py ├── sog.py ├── agreement.py ├── preprocess.py └── analyzer.py └── README.md /lib/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /client/dist: -------------------------------------------------------------------------------- 1 | ../static -------------------------------------------------------------------------------- /server/static: -------------------------------------------------------------------------------- 1 | ../static -------------------------------------------------------------------------------- /lib/version.py: -------------------------------------------------------------------------------- 1 | # Version of MioGatto 2 | VERSION = '1.1.0' 3 | -------------------------------------------------------------------------------- /.flake8: -------------------------------------------------------------------------------- 1 | [flake8] 2 | ignore=D203, E203, E402 3 | max-line-length=119 4 | max-complexity=15 5 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_444444_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_444444_256x240.png -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_555555_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_555555_256x240.png -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_777620_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_777620_256x240.png -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_777777_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_777777_256x240.png -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_cc0000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_cc0000_256x240.png -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wtsnjp/MioGatto/HEAD/static/vendor/jquery-ui-1.12.1/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /client/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2019", 4 | "outDir": "./dist", 5 | "strict": true, 6 | "skipLibCheck": true 7 | }, 8 | //"include": ["./index.ts", "./edit_mcdict.ts"] 9 | } 10 | -------------------------------------------------------------------------------- /lib/datatypes.py: -------------------------------------------------------------------------------- 1 | # Data type definitions 2 | from dataclasses import dataclass 3 | 4 | 5 | @dataclass 6 | class MathIdentifier: 7 | """A type of Math identifier""" 8 | 9 | hexcode: str 10 | var: str 11 | 12 | 13 | @dataclass 14 | class MathConcept: 15 | """A single Math Concept""" 16 | 17 | description: str 18 | arity: int 19 | affixes: list[str] 20 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # ベースイメージを選択(Python 3.9を使用) 2 | FROM python:3.9 3 | 4 | # アプリケーションのディレクトリを作成 5 | WORKDIR /MioGatto 6 | 7 | # ホストのカレントディレクトリにあるファイルをコンテナの/MioGattoディレクトリにコピー 8 | COPY .. /MioGatto/ 9 | 10 | # アプリケーションに必要なパッケージをインストール 11 | RUN apt-get update\ 12 | && apt-get install -y python3-pip\ 13 | && pip install -r requirements.txt 14 | 15 | # アプリケーションを実行 16 | ENTRYPOINT ["python", "-m", "server", "--host", "0.0.0.0"] -------------------------------------------------------------------------------- /client/webpack.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | mode: 'production', 3 | entry: { 4 | 'index': './index.ts', 5 | 'edit_mcdict': './edit_mcdict.ts', 6 | }, 7 | output: { 8 | filename: '[name].js', 9 | }, 10 | module: { 11 | rules: [ 12 | { 13 | test: /\.ts$/, 14 | use: 'ts-loader', 15 | }, 16 | ], 17 | }, 18 | resolve: { 19 | extensions: [ 20 | '.ts', '.js', 21 | ], 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | blinker==1.6.2 2 | click==8.1.4 3 | contourpy==1.1.0 4 | cycler==0.11.0 5 | docopt==0.6.2 6 | Flask==2.3.2 7 | fonttools==4.40.0 8 | itsdangerous==2.1.2 9 | Jinja2==3.1.2 10 | joblib==1.3.1 11 | kiwisolver==1.4.4 12 | lxml==4.9.3 13 | MarkupSafe==2.1.3 14 | matplotlib==3.7.2 15 | numpy==1.25.0 16 | packaging==23.1 17 | pandas==2.0.3 18 | Pillow==10.0.0 19 | pyparsing==3.0.9 20 | python-dateutil==2.8.2 21 | pytz==2023.3 22 | scikit-learn==1.3.0 23 | scipy==1.11.1 24 | seaborn==0.12.2 25 | six==1.16.0 26 | threadpoolctl==3.1.0 27 | tzdata==2023.3 28 | Werkzeug==2.3.6 29 | -------------------------------------------------------------------------------- /client/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "MioGatto-client", 3 | "version": "1.1.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "build": "webpack" 8 | }, 9 | "keywords": [], 10 | "author": "Takuto Asakura", 11 | "license": "MIT", 12 | "description": "", 13 | "devDependencies": { 14 | "@types/jquery": "^3.5.16", 15 | "@types/jqueryui": "^1.12.17", 16 | "jquery-ui": "^1.13.2", 17 | "ts-loader": "^9.4.3", 18 | "typescript": "^5.0.4", 19 | "webpack": "^5.84.1", 20 | "webpack-cli": "^5.1.1" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /static/edit_mcdict_style.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Style for MioGatto 4 | 5 | Author: Takuto ASAKURA 6 | Version: 2021-10-31 7 | 8 | */ 9 | 10 | .main { 11 | display: block; 12 | width: 1000px; 13 | margin-left: 20px; 14 | margin-right: 20px; 15 | } 16 | 17 | .container { 18 | margin: 0 auto; 19 | width: 1060px; 20 | display: -webkit-flex; 21 | display: flex; 22 | } 23 | 24 | .concept-dialog, .error-dialog { 25 | display: none; 26 | list-style: none; 27 | } 28 | 29 | .error-dialog .ui-dialog-titlebar { 30 | color: white; 31 | background: red; 32 | } -------------------------------------------------------------------------------- /lib/logger.py: -------------------------------------------------------------------------------- 1 | # Custom logger 2 | import logging as log 3 | 4 | 5 | def __set_logger(self, quiet: bool, debug: bool): 6 | level = log.INFO 7 | if quiet: 8 | level = log.WARN 9 | if debug: 10 | level = log.DEBUG 11 | 12 | # use stream handler 13 | handler = log.StreamHandler() 14 | formatter = log.Formatter('%(name)s %(levelname)s: %(message)s') 15 | 16 | # apply settings 17 | handler.setLevel(level) 18 | handler.setFormatter(formatter) 19 | 20 | self.setLevel(level) 21 | self.addHandler(handler) 22 | self.propagate = False 23 | 24 | 25 | def get_logger(name: str): 26 | log.Logger.set_logger = __set_logger 27 | return log.getLogger(name) 28 | 29 | main_logger = get_logger('miogatto') 30 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to MioGatto 2 | 3 | Thanks for considering contributing to MioGatto: feedback, fixes, and ideas are all useful. 4 | 5 | ## Creating pull request 6 | 7 | * Before merging your code into the main branch, it must be approved by at least one reviewer other than yourself 8 | * A branch name should be `/` (e.g., `feature/sog_labeling`) 9 | * `` is one of `feature`, `fix`, `hotfix` 10 | 11 | ## Coding rules 12 | 13 | ### Python 14 | 15 | We use `flake8` for a linter and `black` for a code formatter. 16 | 17 | Our settings for `flake8` is in [`.flake8`](.flake8), so you can simply run: 18 | 19 | ```shell 20 | flake8 21 | ``` 22 | 23 | For formatting python codes, some options should be specified: 24 | 25 | ```shell 26 | black --line-length 119 --skip-magic-trailing-comma --skip-string-normalization 27 | ``` 28 | 29 | ### TypeScript 30 | 31 | Currently we don't have particular coding rules for TypeScript. 32 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright 2021 Takuto Asakura (wtsnjp) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /lib/util.py: -------------------------------------------------------------------------------- 1 | # Common utilities 2 | 3 | 4 | def get_mi2idf(tree): 5 | root = tree.getroot() 6 | mi2idf = dict() 7 | 8 | # dirty settings 9 | non_identifiers = [ 10 | 'e280a6', # HORIZONTAL ELLIPSIS (…) 11 | 'e28baf', # MIDLINE HORIZONTAL ELLIPSIS (⋯) 12 | 'e28bae', # VERTICAL ELLIPSIS (⋮) 13 | 'e28bb1', # DOWN RIGHT DIAGONAL ELLIPSIS (⋱) 14 | 'e296a1', # QED BOX (□) 15 | ] 16 | 17 | # loop mi in the tree 18 | for e in root.xpath('//mi'): 19 | mi_id = e.attrib.get('id') 20 | 21 | # skip if empty 22 | if e.text is None: 23 | continue 24 | 25 | # get idf hex 26 | idf_hex = e.text.encode().hex() 27 | 28 | # None if non-identifiers 29 | if idf_hex in non_identifiers: 30 | mi2idf[mi_id] = None 31 | continue 32 | 33 | # detect the idf variant 34 | # Note: mathvariant is replaced (None -> default, normal -> roman) 35 | idf_var = e.attrib.get('mathvariant', 'default') 36 | if idf_var == 'normal': 37 | idf_var = 'roman' 38 | 39 | mi2idf[mi_id] = {'idf_hex': idf_hex, 'idf_var': idf_var} 40 | 41 | return mi2idf 42 | -------------------------------------------------------------------------------- /server/templates/edit_mcdict.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 |
15 | 16 |

17 | 18 |

19 |

20 | 21 |
22 |

Edit mcdict!!!!!!!!!!!!

23 |
24 | 25 |
26 |
27 |

Description:
28 |

29 |

Arity:

30 |

Affixes:
31 | {{ affixes }} 32 |

33 |
34 |
35 | 36 |
37 |

{% for message in get_flashed_messages() %} 38 | {{ message }} 39 | {% endfor %}

40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 | 50 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .Python 11 | env/ 12 | build/ 13 | develop-eggs/ 14 | dist/ 15 | downloads/ 16 | eggs/ 17 | .eggs/ 18 | #lib/ 19 | lib64/ 20 | parts/ 21 | sdist/ 22 | var/ 23 | *.egg-info/ 24 | .installed.cfg 25 | *.egg 26 | 27 | # PyInstaller 28 | # Usually these files are written by a python script from a template 29 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 30 | *.manifest 31 | *.spec 32 | 33 | # Installer logs 34 | pip-log.txt 35 | pip-delete-this-directory.txt 36 | 37 | # Unit test / coverage reports 38 | htmlcov/ 39 | .tox/ 40 | .coverage 41 | .coverage.* 42 | .cache 43 | nosetests.xml 44 | coverage.xml 45 | *,cover 46 | .hypothesis/ 47 | 48 | # Translations 49 | *.mo 50 | *.pot 51 | 52 | # Django stuff: 53 | *.log 54 | local_settings.py 55 | 56 | # Flask stuff: 57 | instance/ 58 | .webassets-cache 59 | 60 | # Scrapy stuff: 61 | .scrapy 62 | 63 | # Sphinx documentation 64 | docs/_build/ 65 | 66 | # PyBuilder 67 | target/ 68 | 69 | # Jupyter Notebook 70 | .ipynb_checkpoints 71 | 72 | # pyenv 73 | .python-version 74 | 75 | # celery beat schedule file 76 | celerybeat-schedule 77 | 78 | # dotenv 79 | .env 80 | 81 | # virtualenv 82 | .venv/ 83 | venv/ 84 | venv_*/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | # client 94 | node_modules/ 95 | 96 | # part of the dataset 97 | annotators 98 | arxmliv 99 | data 100 | doc 101 | static/img 102 | sources 103 | 104 | # local stuff 105 | local/ 106 | notebooks 107 | .local.vimrc 108 | static/img/ 109 | results/ 110 | extra 111 | libextra 112 | /templates 113 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright jQuery Foundation and other contributors, https://jquery.org/ 2 | 3 | This software consists of voluntary contributions made by many 4 | individuals. For exact contribution history, see the revision history 5 | available at https://github.com/jquery/jquery-ui 6 | 7 | The following license applies to all parts of this software except as 8 | documented below: 9 | 10 | ==== 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining 13 | a copy of this software and associated documentation files (the 14 | "Software"), to deal in the Software without restriction, including 15 | without limitation the rights to use, copy, modify, merge, publish, 16 | distribute, sublicense, and/or sell copies of the Software, and to 17 | permit persons to whom the Software is furnished to do so, subject to 18 | the following conditions: 19 | 20 | The above copyright notice and this permission notice shall be 21 | included in all copies or substantial portions of the Software. 22 | 23 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 24 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 25 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 26 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 27 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 28 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 29 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 30 | 31 | ==== 32 | 33 | Copyright and related rights for sample code are waived via CC0. Sample 34 | code is defined as all source code contained within the demos directory. 35 | 36 | CC0: http://creativecommons.org/publicdomain/zero/1.0/ 37 | 38 | ==== 39 | 40 | All files located in the node_modules and external directories are 41 | externally maintained libraries used by this software which have their 42 | own licenses; we recommend you read them, as their terms may differ from 43 | the terms above. 44 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-ui", 3 | "title": "jQuery UI", 4 | "description": "A curated set of user interface interactions, effects, widgets, and themes built on top of the jQuery JavaScript Library.", 5 | "version": "1.12.1", 6 | "homepage": "http://jqueryui.com", 7 | "author": { 8 | "name": "jQuery Foundation and other contributors", 9 | "url": "https://github.com/jquery/jquery-ui/blob/1.12.1/AUTHORS.txt" 10 | }, 11 | "main": "ui/widget.js", 12 | "maintainers": [ 13 | { 14 | "name": "Scott González", 15 | "email": "scott.gonzalez@gmail.com", 16 | "url": "http://scottgonzalez.com" 17 | }, 18 | { 19 | "name": "Jörn Zaefferer", 20 | "email": "joern.zaefferer@gmail.com", 21 | "url": "http://bassistance.de" 22 | }, 23 | { 24 | "name": "Mike Sherov", 25 | "email": "mike.sherov@gmail.com", 26 | "url": "http://mike.sherov.com" 27 | }, 28 | { 29 | "name": "TJ VanToll", 30 | "email": "tj.vantoll@gmail.com", 31 | "url": "http://tjvantoll.com" 32 | }, 33 | { 34 | "name": "Felix Nagel", 35 | "email": "info@felixnagel.com", 36 | "url": "http://www.felixnagel.com" 37 | }, 38 | { 39 | "name": "Alex Schmitz", 40 | "email": "arschmitz@gmail.com", 41 | "url": "https://github.com/arschmitz" 42 | } 43 | ], 44 | "repository": { 45 | "type": "git", 46 | "url": "git://github.com/jquery/jquery-ui.git" 47 | }, 48 | "bugs": "https://bugs.jqueryui.com/", 49 | "license": "MIT", 50 | "scripts": { 51 | "test": "grunt" 52 | }, 53 | "dependencies": {}, 54 | "devDependencies": { 55 | "commitplease": "2.3.0", 56 | "grunt": "0.4.5", 57 | "grunt-bowercopy": "1.2.4", 58 | "grunt-cli": "0.1.13", 59 | "grunt-compare-size": "0.4.0", 60 | "grunt-contrib-concat": "0.5.1", 61 | "grunt-contrib-csslint": "0.5.0", 62 | "grunt-contrib-jshint": "0.12.0", 63 | "grunt-contrib-qunit": "1.0.1", 64 | "grunt-contrib-requirejs": "0.4.4", 65 | "grunt-contrib-uglify": "0.11.1", 66 | "grunt-git-authors": "3.1.0", 67 | "grunt-html": "6.0.0", 68 | "grunt-jscs": "2.1.0", 69 | "load-grunt-tasks": "3.4.0", 70 | "rimraf": "2.5.1", 71 | "testswarm": "1.1.0" 72 | }, 73 | "keywords": [] 74 | } 75 | -------------------------------------------------------------------------------- /lib/annotation.py: -------------------------------------------------------------------------------- 1 | # Annotation data handler 2 | import json 3 | from pathlib import Path 4 | from logging import Logger 5 | from dataclasses import asdict 6 | 7 | from lib.datatypes import MathConcept 8 | 9 | from lib.logger import main_logger 10 | 11 | def dump_json(data, fp): 12 | json.dump(data, fp, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')) 13 | fp.write('\n') 14 | 15 | logger = main_logger.getChild('annotation') 16 | 17 | class MiAnno: 18 | """Math identifier annotation""" 19 | 20 | def __init__(self, file: Path) -> None: 21 | with open(file, encoding='utf-8') as f: 22 | data = json.load(f) 23 | 24 | if data.get('_anno_version', '') != '1.0': 25 | logger.warning('%s: Annotation data version is incompatible', file) 26 | 27 | self.file = file 28 | self.anno_version: str = data.get('_anno_version', 'unknown') 29 | self.annotator: str = data.get('_annotator', 'unknown') 30 | self.occr: dict = data['mi_anno'] 31 | 32 | 33 | def dump(self) -> None: 34 | with open(self.file, 'w') as f: 35 | dump_json( 36 | { 37 | '_anno_version': self.anno_version, 38 | '_annotator': self.annotator, 39 | 'mi_anno': self.occr, 40 | }, 41 | f, 42 | ) 43 | 44 | 45 | class McDict: 46 | """Math concept dictionariy""" 47 | 48 | def __init__(self, file: Path) -> None: 49 | with open(file, encoding='utf-8') as f: 50 | data = json.load(f) 51 | 52 | if data.get('_mcdict_version', '') != '1.0': 53 | logger.warning('%s: Math concept dict version is incompatible', file) 54 | 55 | self.file = file 56 | self.author: str = data.get('_author', 'unknown') 57 | self.mcdict_version: str = data.get('_mcdict_version', 'unknown') 58 | 59 | concepts, surfaces = dict(), dict() 60 | for idf_hex, obj in data['concepts'].items(): 61 | concepts[idf_hex] = dict() 62 | surfaces[idf_hex] = obj['_surface'] 63 | 64 | for idf_var, cls in obj['identifiers'].items(): 65 | concepts[idf_hex][idf_var] = [MathConcept(**c) for c in cls] 66 | 67 | self.concepts = concepts 68 | self.surfaces = surfaces 69 | 70 | def dump(self): 71 | concepts = dict() 72 | for idf_hex, s in self.surfaces.items(): 73 | concepts[idf_hex] = { 74 | '_surface': s, 75 | 'identifiers': dict(), 76 | } 77 | 78 | for idf_var, cls in self.concepts[idf_hex].items(): 79 | concepts[idf_hex]['identifiers'][idf_var] = [asdict(c) for c in cls] 80 | 81 | with open(self.file, 'w') as f: 82 | dump_json( 83 | { 84 | '_author': self.author, 85 | '_mcdict_version': self.mcdict_version, 86 | 'concepts': concepts, 87 | }, 88 | f, 89 | ) 90 | -------------------------------------------------------------------------------- /tools/migrate_data_02to10.py: -------------------------------------------------------------------------------- 1 | # Usage: python -m tools.migrate_data_02to10 2 | import sys 3 | import json 4 | from pathlib import Path 5 | 6 | 7 | def write_json(fp, content): 8 | with open(fp, mode='w') as f: 9 | json.dump(content, f, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')) 10 | 11 | 12 | def process_anno(original_file, new_data_dir): 13 | with open(original_file, encoding='utf-8') as f: 14 | data = json.load(f) 15 | 16 | if data.get('anno_version') != '0.2': 17 | print(f'Anno version of "{original_file}" is not 0.2, skipping', file=sys.stderr) 18 | return 19 | 20 | # metadata 21 | annotator = data['annotator'] 22 | del data['anno_version'] 23 | del data['annotator'] 24 | data['_anno_version'] = '1.0' 25 | data['_annotator'] = annotator 26 | 27 | # data update 28 | for mi in data['mi_anno'].values(): 29 | old_sog_ls = mi['sog'] 30 | new_sog_ls = [] 31 | 32 | for tp in old_sog_ls: 33 | new_sog_ls.append({'start': tp[0], 'stop': tp[1], 'type': 0}) 34 | 35 | mi['sog'] = new_sog_ls 36 | 37 | # write data 38 | filename = original_file.name 39 | write_json(new_data_dir / filename, data) 40 | 41 | 42 | def process_mcdict(original_file, new_data_dir): 43 | with open(original_file, encoding='utf-8') as f: 44 | data = json.load(f) 45 | 46 | if data.get('mcdict_version') != '0.2': 47 | print(f'Anno version of "{original_file}" is not 0.2, skipping', file=sys.stderr) 48 | return 49 | 50 | # metadata 51 | author = data['annotator'] 52 | del data['mcdict_version'] 53 | del data['annotator'] 54 | data['_mcdict_version'] = '1.0' 55 | data['_author'] = author 56 | 57 | # data update 58 | for obj in data['concepts'].values(): 59 | surface = obj['surface'] 60 | del obj['surface'] 61 | obj['_surface'] = surface 62 | 63 | for concept_ls in obj['identifiers'].values(): 64 | for concept in concept_ls: 65 | affixes = concept['args_type'] 66 | del concept['args_type'] 67 | concept['affixes'] = affixes 68 | 69 | # write data 70 | filename = original_file.name 71 | write_json(new_data_dir / filename, data) 72 | 73 | 74 | def main(): 75 | if len(sys.argv) < 3: 76 | print('Not enough arguments are given', file=sys.stderr) 77 | exit(1) 78 | 79 | original_data_dir = Path(sys.argv[1]) 80 | new_data_dir = Path(sys.argv[2]) 81 | 82 | # dir varidations 83 | if not original_data_dir.is_dir(): 84 | print(f'{original_data_dir} is not an existing dir', file=sys.stderr) 85 | exit(1) 86 | 87 | if new_data_dir.exists(): 88 | print(f'{new_data_dir} already exists', file=sys.stderr) 89 | exit(1) 90 | 91 | new_data_dir.mkdir(parents=True) 92 | 93 | # process all data files 94 | for anno_file in original_data_dir.glob('*_anno.json'): 95 | process_anno(anno_file, new_data_dir) 96 | 97 | for mcdict_file in original_data_dir.glob('*_mcdict.json'): 98 | process_mcdict(mcdict_file, new_data_dir) 99 | 100 | 101 | if __name__ == '__main__': 102 | main() 103 | -------------------------------------------------------------------------------- /static/style.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Style for MioGatto 4 | 5 | Author: Takuto ASAKURA 6 | Version: 2021-10-31 7 | 8 | */ 9 | 10 | .main { 11 | display: block; 12 | width: 660px; 13 | margin-left: 20px; 14 | margin-right: 20px; 15 | } 16 | 17 | .main mi { 18 | cursor: pointer; 19 | } 20 | 21 | .main img { 22 | max-width: 100%; 23 | } 24 | 25 | .sidebar { 26 | width: 350px; 27 | padding: 5px; 28 | height: 98vh; 29 | position: sticky; 30 | top: 5px; 31 | bottom: 5px; 32 | } 33 | 34 | .sidebar-tabs { 35 | padding: 10px; 36 | height: 95%; 37 | overflow: auto; 38 | position: sticky; 39 | top: 10px; 40 | bottom: 10px; 41 | } 42 | 43 | .sidebar-tab input.tab-title { 44 | position: absolute; 45 | z-index: -1; 46 | opacity: 0; 47 | } 48 | 49 | .sidebar-tab label.tab-title { 50 | font-weight: bold; 51 | font-family: sans-serif; 52 | line-height: 3; 53 | position: relative; 54 | display: block; 55 | padding: 0 0 0 1em; 56 | cursor: pointer; 57 | margin: 0 0 1px 0; 58 | color: #fff; 59 | background: #da3c41; 60 | } 61 | 62 | .sidebar-tab .tab-content { 63 | overflow: hidden; 64 | word-break: break-word; 65 | max-height: 0; 66 | -webkit-transition: max-height 0.35s; 67 | transition: max-height 0.35s; 68 | color: #333333; 69 | background: #f1c6c6; 70 | } 71 | 72 | .sidebar-tab .tab-content p { 73 | margin: 1em; 74 | } 75 | 76 | /* checked */ 77 | .sidebar-tab input.tab-title:checked ~ .tab-content { 78 | max-height: none; 79 | } 80 | 81 | /* icon */ 82 | .sidebar-tab label.tab-title::after { 83 | line-height: 3; 84 | position: absolute; 85 | top: 0; 86 | right: 0; 87 | display: block; 88 | width: 3em; 89 | height: 3em; 90 | -webkit-transition: all 0.35s; 91 | transition: all 0.35s; 92 | text-align: center; 93 | } 94 | 95 | .sidebar-tab input.tab-title[type=checkbox] + label.tab-title::after { 96 | content: '+'; 97 | } 98 | 99 | .sidebar-tab input.tab-title[type=checkbox]:checked + label.tab-title::after { 100 | transform: rotate(315deg); 101 | } 102 | 103 | .sidebar-tab .tab-content form { 104 | padding: 10px 10px 0px 10px; 105 | } 106 | 107 | .sidebar-tab div.keep input { 108 | display: block; 109 | float: left; 110 | } 111 | 112 | .sidebar-tab div.keep span.keep { 113 | display: block; 114 | overflow: hidden; 115 | } 116 | 117 | .container { 118 | margin: 0 auto; 119 | width: 1060px; 120 | display: -webkit-flex; 121 | display: flex; 122 | } 123 | 124 | .sog-menu { 125 | padding: 0.5em 1em; 126 | margin: 2em 0; 127 | /* color: #5d627b; */ 128 | background: #fff; 129 | border: solid 2px; 130 | /* box-shadow: 0 3px 5px rgba(0, 0, 0, 0.22); */ 131 | display: none; 132 | list-style: none; 133 | position: absolute; 134 | z-index: 1; 135 | } 136 | 137 | .sog-menu-wrap { 138 | display: flex; 139 | flex-flow: column; 140 | } 141 | 142 | .sog-menu input.sog-del:hover { 143 | background: #ff0000; 144 | color: #ffffff; 145 | } 146 | 147 | .concept-dialog, .sog-type-dialog, .error-dialog { 148 | display: none; 149 | list-style: none; 150 | } 151 | 152 | .error-dialog .ui-dialog-titlebar { 153 | color: white; 154 | background: red; 155 | } 156 | 157 | table[class*="ltx_eqn_table"] { 158 | display: block; 159 | overflow-x: scroll; 160 | } 161 | 162 | table[class*="ltx_eqn_table"] td { 163 | padding-bottom: 12px; 164 | } -------------------------------------------------------------------------------- /server/__main__.py: -------------------------------------------------------------------------------- 1 | # The Flask application 2 | from flask import Flask 3 | import os 4 | import lxml.html 5 | from docopt import docopt 6 | from pathlib import Path 7 | 8 | from lib.version import VERSION 9 | from lib.annotation import MiAnno, McDict 10 | from server.miogatto import MioGattoServer 11 | 12 | # meta 13 | PROG_NAME = "server" 14 | HELP = """The server implementation for MioGatto 15 | 16 | Usage: 17 | {p} [options] ID 18 | 19 | Options: 20 | -d DIR, --data=DIR 21 | Dir for the gold data [default: ./data] 22 | -s DIR, --sources=DIR 23 | Dir for preprocessed HTML [default: ./sources] 24 | 25 | -D, --debug Run in the debug mode 26 | -p, --port=NUM Port number [default: 4100] 27 | --host=HOST Host name [default: localhost] 28 | 29 | -h, --help Show this screen and exit 30 | -V, --version Show version 31 | """.format( 32 | p=PROG_NAME 33 | ) 34 | 35 | 36 | # the web app 37 | app = Flask(__name__) 38 | app.secret_key = os.urandom(12) 39 | 40 | 41 | def routing_functions(server): 42 | @app.route('/', methods=['GET']) 43 | def index(): 44 | return server.index() 45 | 46 | @app.route('/_concept', methods=['POST']) 47 | def action_concept(): 48 | return server.assign_concept() 49 | 50 | @app.route('/_remove_concept', methods=['POST']) 51 | def action_remove_concept(): 52 | return server.remove_concept() 53 | 54 | @app.route('/_new_concept', methods=['POST']) 55 | def action_new_concept(): 56 | return server.new_concept() 57 | 58 | @app.route('/_update_concept', methods=['POST']) 59 | def action_update_concept(): 60 | return server.update_concept() 61 | 62 | @app.route('/_update_concept_for_edit_mcdict', methods=['POST']) 63 | def action_update_concept_for_edit_mcdict(): 64 | return server.update_concept_for_edit_mcdict() 65 | 66 | @app.route('/_add_sog', methods=['POST']) 67 | def action_add_sog(): 68 | return server.add_sog() 69 | 70 | @app.route('/_delete_sog', methods=['POST']) 71 | def action_delete_sog(): 72 | return server.delete_sog() 73 | 74 | @app.route('/_change_sog_type', methods=['POST']) 75 | def action_change_sog_type(): 76 | return server.change_sog_type() 77 | 78 | @app.route('/mcdict.json', methods=['GET']) 79 | def mcdict_json(): 80 | return server.gen_mcdict_json() 81 | 82 | @app.route('/sog.json', methods=['GET']) 83 | def sog_json(): 84 | return server.gen_sog_json() 85 | 86 | @app.route('/edit_mcdict', methods=['GET']) 87 | def edit_mcdict(): 88 | return server.edit_mcdict() 89 | 90 | 91 | def main(): 92 | # parse options 93 | args = docopt(HELP, version=VERSION) 94 | 95 | paper_id = args['ID'] 96 | 97 | # dir and files 98 | data_dir = Path(args['--data']) 99 | sources_dir = Path(args['--sources']) 100 | 101 | anno_json = data_dir / '{}_anno.json'.format(paper_id) 102 | mcdict_json = data_dir / '{}_mcdict.json'.format(paper_id) 103 | source_html = sources_dir / '{}.html'.format(paper_id) 104 | 105 | # load the data 106 | mi_anno = MiAnno(anno_json) 107 | mcdict = McDict(mcdict_json) 108 | tree = lxml.html.parse(str(source_html)) 109 | 110 | # run the app 111 | app.debug = args['--debug'] 112 | 113 | server = MioGattoServer(paper_id, tree, mi_anno, mcdict, app.logger) 114 | routing_functions(server) 115 | 116 | app.run(host=args['--host'], port=args['--port']) 117 | 118 | 119 | if __name__ == '__main__': 120 | main() 121 | -------------------------------------------------------------------------------- /static/edit_mcdict.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";function t(t){let e={};var n;e.hex=(n=t.text(),Array.from((new TextEncoder).encode(n)).map((t=>t.toString(16))).join("")),e.var="default";let i=t.attr("mathvariant");null!=i&&(e.var="normal"==i?"roman":i);let a=t.data("math-concept");return null!=a&&(e.concept=Number(a)),e}function e(n){let a=[];n.is("mi")&&null!=function(t){if(null!=i[t.hex])return i[t.hex][t.var]}(t(n))&&(a=[n]);for(let t=0;t?@\[\\\]^`{|}~]/g,"\\$&")));r.hex==e&&r.var==n&&null!=r.concept&&r.concept==i&&(a+=1)}return a}function u(t){let e=Array();for(let n=0;n${a}`:`${a}`;let r="";if(0==i[e][n].length){let t=c(e,n);r=`${o}${t[0]}/${t[1]}No candidate concepts`}else{let t=0;for(let a in i[e][n]){let l=i[e][n][a];if(null!=l.description){let u="NONE";l.affixes.length>0&&(u=l.affixes.join(", "));let h="";if(0==t){let t=c(e,n),a=t[0],r=t[1];h=`${o}${a}/${r}`}let p=d(e,n,Number(a)),s=f(e,n,Number(a));r+=`${h}${l.description}${u}${l.arity}${p}${s}edit`,t+=1}}}t+=r}let e=`${t}
IdentifierProgressDescriptionAffixArity#Occur#SogEdit
`;$("#edit-mcdict-box").html(e),$("a.edit-concept-mcdict").on("click",(function(){let t=$(this).attr("data-idf-hex"),e=$(this).attr("data-idf-var"),a=$(this).attr("data-concept");!function(t,e){let a=$("#concept-dialog-template").clone();a.removeAttr("id");let o=a.find("#concept-form");o.attr("action","/_update_concept_for_edit_mcdict");let r=i[t.hex][t.var][e];o.find("textarea").text(r.description),o.find('input[name="arity"]').attr("value",r.arity),r.affixes.forEach((function(t,e){o.find(`select[name="affixes${e}"]`).find(`option[value="${t}"]`).prop("selected",!0)})),a.dialog({modal:!0,title:"Edit Concept",width:500,buttons:{OK:function(){localStorage.scroll_top=$(window).scrollTop(),o.append(``),o.append(``),o.append(``),o.append(``),o.trigger("submit")},Cancel:function(){$(this).dialog("close")}}})}({hex:t,var:e,concept:a},Number(a))}))})),$((function(){$("button#back-to-index").button(),$("button#back-to-index").on("click",(function(){let t=$("#back-to-index-form");t.attr("action","/"),t.trigger("submit")}))}))})(); -------------------------------------------------------------------------------- /tools/sog.py: -------------------------------------------------------------------------------- 1 | # An analysis script for sources of grounding 2 | import lxml.html 3 | import numpy as np 4 | from docopt import docopt 5 | from pathlib import Path 6 | 7 | from lib.version import VERSION 8 | from lib.logger import main_logger 9 | from lib.util import get_mi2idf 10 | from lib.annotation import MiAnno, McDict 11 | 12 | # meta 13 | PROG_NAME = "tools.sog" 14 | HELP = """An analysis script for sources of grounding 15 | 16 | Usage: 17 | {p} [options] ID 18 | 19 | Options: 20 | -d DIR, --data=DIR Dir for the gold data [default: ./data] 21 | --sources=DIR Dir for preprocessed HTML [default: ./sources] 22 | 23 | -s, --show-sog Show actual SoG by concept 24 | -D, --debug Show debug messages 25 | -q, --quiet Show less messages 26 | 27 | -h, --help Show this screen and exit 28 | -V, --version Show version 29 | """.format(p=PROG_NAME) 30 | 31 | logger = main_logger.getChild(PROG_NAME) 32 | 33 | 34 | def analyze_sog(tree, mi_anno: MiAnno, mcdict: McDict) -> dict: 35 | mi2idf = get_mi2idf(tree) 36 | root = tree.getroot() 37 | 38 | # prepare the word info 39 | wl, words = [], dict() 40 | for e in root.xpath('//span[@class="gd_word"]'): 41 | w_id = e.attrib.get('id') 42 | wl.append(w_id) 43 | if type(e.text) is str: 44 | words[w_id] = e.text 45 | # TODO: check for the else case 46 | 47 | # initialize sog_by_concept 48 | sog_by_concept = { 49 | idf_hex: { 50 | idf_var: [[] for _ in cs] 51 | for idf_var, cs in v.items() 52 | } 53 | for idf_hex, v in mcdict.concepts.items() 54 | } 55 | 56 | # get actual text 57 | for mi_id, anno in mi_anno.occr.items(): 58 | for sog in anno['sog']: 59 | w_ids = wl[wl.index(sog['start']):wl.index(sog['stop']) + 1] 60 | idf, c_id = mi2idf[mi_id], anno['concept_id'] 61 | idf_hex, idf_var = idf['idf_hex'], idf['idf_var'] 62 | sog_by_concept[idf_hex][idf_var][c_id].append(' '.join([ 63 | words[w_id] for w_id in w_ids if words.get(w_id) is not None 64 | ])) 65 | 66 | return sog_by_concept 67 | 68 | 69 | def main(): 70 | # parse options 71 | args = docopt(HELP, version=VERSION) 72 | 73 | main_logger.set_logger(args['--quiet'], args['--debug']) 74 | paper_id = args['ID'] 75 | 76 | # dirs and files 77 | data_dir = Path(args['--data']) 78 | 79 | sources_dir = Path(args['--sources']) 80 | source_html = sources_dir / '{}.html'.format(paper_id) 81 | 82 | anno_json = data_dir / '{}_anno.json'.format(paper_id) 83 | mcdict_json = data_dir / '{}_mcdict.json'.format(paper_id) 84 | 85 | # load the data 86 | mi_anno = MiAnno(anno_json) 87 | mcdict = McDict(mcdict_json) 88 | 89 | # analyze and show the results 90 | tree = lxml.html.parse(str(source_html)) 91 | sog_by_concept = analyze_sog(tree, mi_anno, mcdict) 92 | 93 | print('* Metadata') 94 | print('Paper ID: {}'.format(paper_id)) 95 | print('Author of math concept dict: {}'.format(mi_anno.annotator)) 96 | print('Annotator: {}'.format(mcdict.author)) 97 | print() 98 | 99 | print('* Number of SoG by concept') 100 | nof_sogs = [ 101 | len(sogs) for v in sog_by_concept.values() for cs in v.values() 102 | for sogs in cs 103 | ] 104 | print('Max: {}'.format(max(nof_sogs))) 105 | print('Median: {}'.format(int(np.median(nof_sogs)))) 106 | print('Mean: {:.1f}'.format(np.mean(nof_sogs))) 107 | print('Variance: {:.1f}'.format(np.var(nof_sogs))) 108 | print('Standard deviation: {:.1f}'.format(np.std(nof_sogs))) 109 | print('#zeros: {}'.format(nof_sogs.count(0))) 110 | print() 111 | 112 | if not args['--show-sog']: 113 | exit(0) 114 | 115 | print('* Actual SoG by concept') 116 | for idf_hex, v in sog_by_concept.items(): 117 | for idf_var, cs in v.items(): 118 | print('{} ({})'.format(mcdict.surfaces[idf_hex]['text'], idf_var)) 119 | for cid, sogs in enumerate(cs): 120 | print(' - {}'.format( 121 | mcdict.concepts[idf_hex][idf_var][cid].description)) 122 | for idx, sog in enumerate(sogs): 123 | print(' {}. {}'.format(idx + 1, sog)) 124 | 125 | 126 | if __name__ == '__main__': 127 | main() 128 | -------------------------------------------------------------------------------- /server/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ title }} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 |
18 |
19 | 20 |
21 |
22 |
23 |
24 | 25 | 26 |
27 |
28 |
29 | 30 |
31 |
32 |
33 |
34 | 35 |
36 |
37 |
38 | 39 |
40 |
41 | 42 |
43 |
44 |

Description:
45 |

46 |

Arity:

47 |

Affixes:
48 | {{ affixes }} 49 |

50 |
51 |
52 | 53 |
54 |
55 |
56 |
57 | 58 |
59 |
60 | 61 |
62 |

{% for message in get_flashed_messages() %} 63 | {{ message }} 64 | {% endfor %}

65 |
66 | 67 | {{ main_content }} 68 |
69 | 70 | 136 | 137 |
138 | 139 | 140 | -------------------------------------------------------------------------------- /client/common.ts: -------------------------------------------------------------------------------- 1 | // -------------------------- 2 | // Type declaration 3 | // -------------------------- 4 | 5 | export interface Identifier { 6 | hex: string; 7 | var: string; 8 | concept?: number; 9 | } 10 | 11 | export interface Concept { 12 | affixes: string[]; 13 | arity: number; 14 | description: string; 15 | color?: string; 16 | } 17 | 18 | export interface Source { 19 | mi_id: string; 20 | start_id: string; 21 | stop_id: string; 22 | type: number; // 0: declaration, 1: definition, 2: others 23 | } 24 | 25 | // -------------------------- 26 | // utility 27 | // -------------------------- 28 | 29 | // escape for jQuery selector 30 | export function escape_selector(raw: string) { 31 | return raw.replace(/[ !"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g, "\\$&"); 32 | } 33 | 34 | // convert UTF-8 string to hex string 35 | export function hex_encode(str: string) { 36 | let arr = Array.from((new TextEncoder()).encode(str)).map( 37 | v => v.toString(16)); 38 | return arr.join(''); 39 | } 40 | 41 | // construct the idf dict from a mi element 42 | export function get_idf(elem: JQuery) { 43 | let idf = {} as Identifier; 44 | idf.hex = hex_encode(elem.text()); 45 | idf.var = 'default'; 46 | 47 | let var_cand = elem.attr('mathvariant'); 48 | if(var_cand != undefined) { 49 | if(var_cand == 'normal') { 50 | idf.var = 'roman'; 51 | } else { 52 | idf.var = var_cand; 53 | } 54 | } 55 | 56 | let concept_cand = elem.data('math-concept'); 57 | if(concept_cand != undefined) 58 | idf.concept = Number(concept_cand); 59 | 60 | return idf; 61 | } 62 | 63 | // accessors 64 | export function get_concept(idf: Identifier) { 65 | if(idf.concept != undefined) { 66 | return mcdict[idf.hex][idf.var][idf.concept]; 67 | } else { 68 | return undefined; 69 | } 70 | } 71 | 72 | export function get_concept_cand(idf: Identifier) { 73 | if(mcdict[idf.hex] != undefined) 74 | return mcdict[idf.hex][idf.var]; // can be undefined 75 | } 76 | 77 | // convert color code from hex to rgb 78 | export function hex2rgb(hex: string) { 79 | if(hex.slice(0, 1) == "#") { 80 | hex = hex.slice(1); 81 | } 82 | if(hex.length == 3) { 83 | hex = hex.slice(0, 1) + hex.slice(0, 1) + hex.slice(1, 2) + hex.slice(1, 2) + hex.slice(2, 3) + hex.slice(2, 3); 84 | } 85 | 86 | return [hex.slice(0, 2), hex.slice(2, 4), hex.slice(4, 6)].map(function(str) { 87 | return parseInt(str, 16); 88 | }); 89 | } 90 | 91 | export function dfs_mis(cur_node: JQuery): JQuery[] { 92 | 93 | let obtained_mis: JQuery[] = []; 94 | 95 | // Add current node if its mi. 96 | // Only consider the mis in mcdict. 97 | if((cur_node.is('mi')) && (get_concept_cand(get_idf(cur_node)) != undefined)){ 98 | obtained_mis = [cur_node]; 99 | } 100 | 101 | // DFS search the children. 102 | for (let i = 0; i < cur_node.children().length; i++){ 103 | let child = cur_node.children().eq(i); 104 | obtained_mis = obtained_mis.concat(dfs_mis(child)); 105 | } 106 | 107 | return obtained_mis; 108 | } 109 | 110 | // -------------------------- 111 | // Prepare the data 112 | // -------------------------- 113 | 114 | // load from the external json file 115 | export let mcdict_edit_id: number = 0; 116 | export let mcdict = {} as {[key: string]: {[key: string]: Concept[]}}; 117 | $.ajax({ 118 | url: '/mcdict.json', 119 | dataType: 'json', 120 | async: false, 121 | success: function(data) { 122 | // Data is extended to include mcdict version. 123 | mcdict_edit_id = data[0]; 124 | mcdict = data[1]; 125 | } 126 | }); 127 | 128 | // define color for each concept 129 | let colors = [ 130 | '#008b8b', '#ff7f50', '#ff4500', '#2f4f4f', '#006400', '#dc143c', 131 | '#c71585', '#4169e1', '#2e8b57', '#ff1493', '#191970', '#ff69b4', 132 | '#ff69b4', '#0000cd', '#f4a460', '#ff00ff', '#7cfc00', '#d2691e', 133 | '#a0522d', '#800000', '#9400d3', '#556b2f', '#4b0082', '#808000' 134 | ]; 135 | 136 | let cnt = 0; 137 | for(let idf_hex in mcdict) { 138 | for(let idf_var in mcdict[idf_hex]) { 139 | for(let concept in mcdict[idf_hex][idf_var]) { 140 | if(mcdict[idf_hex][idf_var][concept].description != undefined) { 141 | mcdict[idf_hex][idf_var][concept].color = colors[cnt % colors.length]; 142 | cnt++; 143 | } 144 | } 145 | } 146 | } 147 | 148 | // load sog from the external json file 149 | export let sog = {} as {sog: Source[]}; 150 | $.ajax({ 151 | url: '/sog.json', 152 | dataType: 'json', 153 | async: false, 154 | success: function(data) { 155 | sog = data; 156 | } 157 | }); 158 | 159 | 160 | // -------------------------- 161 | // Error from the server 162 | // -------------------------- 163 | 164 | $(function() { 165 | if($('#error-message').text().length != 0) { 166 | $('#error-dialog').dialog({ 167 | dialogClass: 'error-dialog', 168 | modal: true, 169 | title: 'Error', 170 | buttons: { 171 | "OK": function() { 172 | $(this).dialog('close'); 173 | } 174 | } 175 | }); 176 | } 177 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MioGatto: Math Identifier-oriented Grounding Annotation Tool 2 | 3 | ## System requirements 4 | 5 | * Python3 (3.9 or later) 6 | * A Web Browser with MathML support (for the GUI annotation system) 7 | * [Firefox](https://www.mozilla.org/firefox/) is recommended 8 | 9 | ## Installation 10 | 11 | The dependencies will be all installed with one shot: 12 | 13 | ```shell 14 | python -m pip install -r requirements.txt 15 | ``` 16 | 17 | In case you don't want to install the dependencies into your system, please 18 | consider using [venv](https://docs.python.org/3/library/venv.html). 19 | 20 | ## Project structure 21 | 22 | ### Files in this repository 23 | 24 | All the components of MioGatto is included in this repository: 25 | 26 | * `lib/` contains the project library. 27 | * `server/` contains the implementation of the server. 28 | * `client/` contains the implementation of the client. 29 | * `tools/` contains our utility Python scripts. 30 | 31 | ### Files not in this repository 32 | 33 | On the other hand, the annotation data is not included in this repository due 34 | to the NDA constrain for [the arXMLiv dataset](https://sigmathling.kwarc.info/resources/arxmliv-dataset-2020/). The data is licensed to 35 | [SIGMathLing members](https://sigmathling.kwarc.info/member/) as [Dataset for 36 | Grounding of Formulae](https://sigmathling.kwarc.info/resources/grounding-dataset/). 37 | Please consider joining [SIGMathLing](https://sigmathling.kwarc.info/member/) 38 | to acquire the dataset. 39 | 40 | * `arxmliv/` contains the original documents from the arXMLiv dataset 41 | * `data/` contains the annotation data 42 | * `sources/` contains the preprocessed documents 43 | 44 | ## Annotator's guide 45 | 46 | For the guide with GIF animation, please refer to our Wiki: 47 | 48 | * 49 | 50 | ## Prepare the input and analyze the annotated data (Advanced) 51 | 52 | The Python scripts under the `tools` directory are mostly for the developers 53 | for the grounding dataset. The `--help` (`-h`) option is available for all 54 | scripts and should provide guides to their basic usages. 55 | 56 | ### Preparing data 57 | 58 | As mentioned above, the HTML5 files in [the arXMLiv dataset](https://sigmathling.kwarc.info/resources/arxmliv-dataset-2020/) 59 | are suitable as the input document for MioGatto. Alternatively, you can provide 60 | the equivalent HTML5 files from LaTeX sources by using 61 | [LaTeXML](https://dlmf.nist.gov/LaTeXML/): 62 | 63 | ```shell 64 | latexmlc --preload=[nobibtex,ids,mathlexemes,localrawstyles]latexml.sty --format=html5 --pmml --cmml --mathtex --nodefaultresources --dest= 65 | ``` 66 | 67 | Then you can give the HTML5 files to our preprocess script: 68 | 69 | ```shell 70 | python -m tools.preprocess 71 | ``` 72 | 73 | This will output the preprocessed HTML file to the `sources/` and generate the 74 | initialized JSON files for the annotation to the `data/` by default. Please 75 | refer to the help message for the options. 76 | 77 | ```shell 78 | python -m tools.preprocess -h 79 | ``` 80 | 81 | ### Analysing the annotation results 82 | 83 | For the basic analyses for annotation data, execute: 84 | 85 | ```shell 86 | python -m tools.analyzer 87 | ``` 88 | 89 | Some supplemental files including graph images will be saved in the `results` 90 | directory as default. 91 | 92 | Similarly, analyses for the sources of grounding annotation can be performed 93 | with the `tools.sog` script. 94 | 95 | ```shell 96 | python -m tools.sog 97 | ``` 98 | 99 | To calculate agreements between data by two annotators, execute: 100 | 101 | ```shell 102 | python -m tools.agreement --target= 103 | ``` 104 | 105 | ## Developing client 106 | 107 | The client is developed with TypeScript. All development tools will be 108 | installed with: 109 | 110 | ```shell 111 | cd client 112 | npm install 113 | ``` 114 | 115 | To compile the client source `client/index.ts`, execute the following in the 116 | client directory: 117 | 118 | ```shell 119 | npm run build 120 | ``` 121 | 122 | ## Publications 123 | 124 | * Takuto Asakura, Yusuke Miyao. **What Is Needed for Intra-document Disambiguation of Math Identifiers?**. In Proceedings of [The 2024 Joint International Conference on Computational Linguistics, Language Resources and Evaluation (LREC-COLING 2024)](https://lrec-coling-2024.org). 125 | [[paper](https://aclanthology.org/2024.lrec-main.1522/)] [[bib](https://aclanthology.org/2024.lrec-main.1522.bib)] [[poster](https://wtsnjp.com/posters/lrec-coling2024-asakura-poster.pdf)] 126 | * Aamin Dev, Takuto Asakura, Rune Sætre. **An Approach to Co-reference Resolution and Formula Grounding for Mathematical Identifiers using Large Language Models**. In Proceedings of [The 2nd Workshop on Mathematical Natural Language Processing (MathNLP 2024)](https://sites.google.com/view/2nd-mathnlp). 127 | [[paper](https://aclanthology.org/2024.mathnlp-1.1/)] [[bib](https://aclanthology.org/2024.mathnlp-1.1.bib)] 128 | * Takuto Asakura, Yusuke Miyao, Akiko Aizawa. **Building Dataset for Grounding of Formulae — Annotating Coreference Relations Among Math Identifiers**. In Proceedings of [13th Conference on Language Resources and Evaluation (LREC 2022)](https://lrec2022.lrec-conf.org). pp. 4851―4858, 2022. 129 | [[paper](https://aclanthology.org/2022.lrec-1.519/)] [[bib](http://www.lrec-conf.org/proceedings/lrec2022/bib/2022.lrec-1.519.bib)] [[slides](https://speakerdeck.com/wtsnjp/lrec2022)] [[video](http://www.lrec-conf.org/proceedings/lrec2022/media/sessions/935.mp4)] [[resource](https://sigmathling.kwarc.info/resources/grounding-dataset/)] 130 | * Takuto Asakura, Yusuke Miyao, Akiko Aizawa, Michael Kohlhase. **MioGatto: A Math Identifier-oriented Grounding Annotation Tool**. In [13th MathUI Workshop at 14th Conference on Intelligent Computer Mathematics (MathUI 2021)](https://cicm-conference.org/2021/cicm.php?event=MathUI). 131 | [[preprint](https://easychair.org/publications/preprint/FSSk)] [[paper](https://kwarc.info/teaching/CICM21WS/mathui5.pdf)] [[slides](https://speakerdeck.com/wtsnjp/mathui2021)] [[code](https://github.com/wtsnjp/MioGatto)] 132 | * Takuto Asakura, André Greiner-Petter, Akiko Aizawa, Yusuke Miyao. **Towards Grounding of Formulae**. In Proceedings of [First Workshop on Scholarly Document Processing (SDP 2020)](https://ornlcda.github.io/SDProc/). pp. 138―147, 2020. 133 | [[paper](https://www.aclweb.org/anthology/2020.sdp-1.16/)] [[bib](https://www.aclweb.org/anthology/2020.sdp-1.16.bib)] [[poster](https://wtsnjp.com/posters/sdp2020-asakura-poster.pdf)] [[resource](https://sigmathling.kwarc.info/resources/grounding-dataset/)] 134 | * Takuto Asakura, André Greiner-Petter, Akiko Aizawa, Yusuke Miyao. **Dataset Creation for Grounding of Formulae**. In [SCIDOCA 2020](http://research.nii.ac.jp/SCIDOCA2020/). 135 | [[slides](https://speakerdeck.com/wtsnjp/scidoca2020)] [[resource](https://sigmathling.kwarc.info/resources/grounding-dataset/)] 136 | 137 | ## Acknowledgements 138 | 139 | This project has been supported by JST, ACT-X Grant Number JPMJAX2002, Japan. 140 | 141 | ## License 142 | 143 | Copyright 2021 Takuto Asakura ([wtsnjp](https://wtsnjp.com)) 144 | 145 | This software is licensed under [the MIT license](./LICENSE). 146 | 147 | ### Third-party software 148 | 149 | * [jQuery](https://jquery.org/): Copyright JS Foundation and other contributors. Licensed under [the MIT license](https://jquery.org/license). 150 | * [jQuery UI](https://jqueryui.com/): Copyright jQuery Foundation and other contributors. Licensed under [the MIT license](https://github.com/jquery/jquery-ui/blob/HEAD/LICENSE.txt). 151 | 152 | --- 153 | 154 | Takuto Asakura ([wtsnjp](https://wtsnjp.com)) 155 | -------------------------------------------------------------------------------- /client/edit_mcdict.ts: -------------------------------------------------------------------------------- 1 | // the MioGatto client 2 | 'use strict'; 3 | 4 | import {Identifier, Concept, dfs_mis, get_idf, mcdict, mcdict_edit_id, sog, escape_selector} from "./common"; 5 | 6 | // -------------------------- 7 | // Edit mcdict 8 | // -------------------------- 9 | 10 | let mi_list: Identifier[] = []; 11 | 12 | // Update mi_list after loading html. 13 | $(function() { 14 | 15 | // Load mi_list. 16 | for (let mi_jquery of dfs_mis($(":root"))) { 17 | 18 | mi_list.push(get_idf(mi_jquery)); 19 | } 20 | 21 | }); 22 | 23 | // Sending a form specific to edit_mcdict 24 | function edit_concept(idf: Identifier, concept_id: number) { 25 | let concept_dialog = $('#concept-dialog-template').clone(); 26 | concept_dialog.removeAttr('id'); 27 | let form = concept_dialog.find('#concept-form'); 28 | form.attr('action', '/_update_concept_for_edit_mcdict'); 29 | 30 | // put the current values 31 | let concept = mcdict[idf.hex][idf.var][concept_id]; 32 | form.find('textarea').text(concept.description); 33 | form.find('input[name="arity"]').attr('value', concept.arity); 34 | concept.affixes.forEach(function(value, idx) { 35 | form.find(`select[name="affixes${idx}"]`).find( 36 | `option[value="${value}"]`).prop('selected', true); 37 | }) 38 | 39 | concept_dialog.dialog({ 40 | modal: true, 41 | title: 'Edit Concept', 42 | width: 500, 43 | buttons: { 44 | 'OK': function() { 45 | localStorage['scroll_top'] = $(window).scrollTop(); 46 | form.append(``) 47 | form.append(``) 48 | form.append(``) 49 | form.append(``) 50 | form.trigger("submit"); 51 | }, 52 | 'Cancel': function() { 53 | $(this).dialog('close'); 54 | } 55 | } 56 | }); 57 | } 58 | 59 | // Count the annotated idfs. 60 | function count_idf_progress(idf_hex: string, idf_var: string): [number, number] { 61 | let idf_annotated = 0; 62 | let idf_occur = 0; 63 | 64 | for (let mi of mi_list) { 65 | 66 | if ((mi.hex == idf_hex) && (mi.var == idf_var)) { 67 | idf_occur += 1; 68 | 69 | // Check if annotated. 70 | if (mi.concept != undefined) { 71 | idf_annotated += 1; 72 | } 73 | 74 | } 75 | } 76 | 77 | return [idf_annotated, idf_occur]; 78 | } 79 | 80 | // Count the number of occurences. 81 | function count_occur(idf_hex: string, idf_var: string, concept_id: number): number { 82 | let count = 0; 83 | 84 | for (let mi of mi_list) { 85 | 86 | if ((mi.hex == idf_hex) && (mi.var == idf_var) && (mi.concept != undefined) && (mi.concept == concept_id)) { 87 | count += 1; 88 | } 89 | } 90 | 91 | return count; 92 | } 93 | 94 | // Count the number of sogs. 95 | function count_sog(idf_hex: string, idf_var: string, concept_id: number): number { 96 | let count = 0; 97 | 98 | for (let s of sog.sog) { 99 | let sog_idf = get_idf($('#' + escape_selector(s.mi_id))); 100 | 101 | if ((sog_idf.hex == idf_hex) && (sog_idf.var == idf_var) && (sog_idf.concept != undefined) && (sog_idf.concept == concept_id)) { 102 | count += 1; 103 | } 104 | } 105 | 106 | return count; 107 | } 108 | 109 | // convert hex string to UTF-8 string 110 | function hex_decode(str: string) { 111 | let bytes: number[] = Array(); 112 | 113 | // Convert hex to int. 114 | for (let i = 0; i < str.length ; i += 2) { 115 | bytes.push(parseInt(str.slice(i, i + 2), 16)); 116 | } 117 | 118 | //console.log(new Uint8Array(bytes)); 119 | 120 | let decoded: string = (new TextDecoder()).decode(new Uint8Array(bytes)); 121 | return decoded; 122 | } 123 | 124 | // Show identifiers in edit-mcdict-box. 125 | $(function () { 126 | 127 | let table_header = 'IdentifierProgressDescriptionAffixArity#Occur#SogEdit'; 128 | 129 | let table_content = ''; 130 | 131 | for (let idf_hex in mcdict) { 132 | for (let idf_var in mcdict[idf_hex]) { 133 | 134 | // Retrive identifier. 135 | let idf_str = hex_decode(idf_hex); 136 | let idf_elem = ''; 137 | 138 | if (idf_var != 'default') { 139 | idf_elem = `${idf_str}`; 140 | } else { 141 | // Do not set mathvariant. 142 | idf_elem = `${idf_str}`; 143 | } 144 | 145 | // Retrive concepts. 146 | 147 | let candidate_rows = ``; 148 | 149 | if (mcdict[idf_hex][idf_var].length == 0) { 150 | // If there is no candidate concepts. 151 | // Calculate the progress for each identifier. 152 | let idf_progress: [number, number] = count_idf_progress(idf_hex, idf_var); 153 | 154 | let idf_annotated = idf_progress[0]; 155 | let idf_occur = idf_progress[1]; 156 | 157 | candidate_rows = `${idf_elem}${idf_annotated}/${idf_occur}No candidate concepts`; 158 | 159 | } else { 160 | let cand_i = 0; 161 | 162 | for (let concept_id in mcdict[idf_hex][idf_var]) { 163 | let concept: Concept = mcdict[idf_hex][idf_var][concept_id]; 164 | 165 | if (concept.description != undefined) { 166 | 167 | let args_info = 'NONE'; 168 | if(concept.affixes.length > 0) { 169 | args_info = concept.affixes.join(', '); 170 | } 171 | 172 | let idf_column = ''; 173 | if (cand_i == 0){ 174 | 175 | // Calculate the progress for each identifier. 176 | let idf_progress: [number, number] = count_idf_progress(idf_hex, idf_var); 177 | 178 | let idf_annotated = idf_progress[0]; 179 | let idf_occur = idf_progress[1]; 180 | 181 | idf_column = `${idf_elem}${idf_annotated}/${idf_occur}`; 182 | } 183 | 184 | // Calculate the number of occurences and sogs. 185 | 186 | let num_occur = count_occur(idf_hex, idf_var, Number(concept_id)); 187 | 188 | let num_sogs = count_sog(idf_hex, idf_var, Number(concept_id)); 189 | 190 | let concept_row = `${idf_column}${concept.description}${args_info}${concept.arity}${num_occur}${num_sogs}edit`; 191 | 192 | candidate_rows += concept_row; 193 | 194 | cand_i += 1; 195 | 196 | } 197 | } 198 | } 199 | 200 | table_content += candidate_rows 201 | 202 | } 203 | } 204 | 205 | let content = `${table_header}${table_content}
`; 206 | 207 | let mcdict_edit_box = $('#edit-mcdict-box'); 208 | mcdict_edit_box.html(content) 209 | 210 | 211 | // enable concept dialogs 212 | $('a.edit-concept-mcdict').on('click', function() { 213 | let idf_hex = $(this).attr('data-idf-hex'); 214 | let idf_var = $(this).attr('data-idf-var'); 215 | let concept_id = $(this).attr('data-concept'); 216 | 217 | let idf = {'hex': idf_hex, 'var': idf_var, 'concept': concept_id} as Identifier; 218 | 219 | edit_concept(idf, Number(concept_id)); 220 | }); 221 | 222 | }); 223 | 224 | 225 | $(function() { 226 | $('button#back-to-index').button(); 227 | $('button#back-to-index').on('click', function() { 228 | let form = $('#back-to-index-form'); 229 | form.attr('action', '/'); 230 | form.trigger("submit"); 231 | }); 232 | 233 | }); 234 | -------------------------------------------------------------------------------- /tools/agreement.py: -------------------------------------------------------------------------------- 1 | # Agreement calculation tool for MioGatto 2 | import lxml.html 3 | import numpy as np 4 | from docopt import docopt 5 | from pathlib import Path 6 | from sklearn.metrics import cohen_kappa_score 7 | 8 | from lib.version import VERSION 9 | from lib.logger import main_logger 10 | from lib.util import get_mi2idf 11 | from lib.annotation import MiAnno, McDict 12 | 13 | # meta 14 | PROG_NAME = "tools.agreement" 15 | HELP = """Agreement calculation tool for MioGatto 16 | 17 | Usage: 18 | {p} [options] ID 19 | 20 | Options: 21 | -t DIR, --target=DIR Dir for the reference data (Required) 22 | -r DIR, --reference=DIR 23 | Dir for the reference data [default: ./data] 24 | --sources=DIR Dir for preprocessed HTML [default: ./sources] 25 | 26 | -s, --show-mismatch Show mismatch details 27 | -D, --debug Show debug messages 28 | -q, --quiet Show less messages 29 | 30 | -h, --help Show this screen and exit 31 | -V, --version Show version 32 | """.format( 33 | p=PROG_NAME 34 | ) 35 | 36 | logger = main_logger.getChild(PROG_NAME) 37 | 38 | # dirty hack: suspend warning 39 | np.seterr(divide='ignore', invalid='ignore') 40 | 41 | 42 | def extract_info(tree): 43 | mi2idf = get_mi2idf(tree) 44 | root = tree.getroot() 45 | html_str = lxml.html.tostring(tree, encoding='utf-8').decode('utf-8') 46 | 47 | # extract mi info 48 | mi_info = dict() 49 | for e in root.xpath('//mi'): 50 | mi_id = e.attrib.get('id') 51 | 52 | # idf info 53 | idf = mi2idf.get(mi_id) 54 | 55 | if idf is not None: 56 | mi_info[mi_id] = idf 57 | else: 58 | continue 59 | 60 | # position info 61 | pos = html_str.find(lxml.html.tostring(e, encoding='utf-8').decode('utf-8')) 62 | mi_info[mi_id]['pos'] = pos 63 | 64 | # make word list 65 | wl = [e.attrib.get('id') for e in root.xpath('//span[@class="gd_word"]')] 66 | 67 | return mi_info, wl 68 | 69 | 70 | def calc_agreements(ref_mi_anno, target_mi_anno, ref_mcdict, mi_info, show_mismatch): 71 | pos, neg, pt_miss, unannotated = 0, 0, 0, 0 72 | labels = dict() 73 | 74 | if show_mismatch: 75 | print('* Mismatches') 76 | print('ID\tReference Concept\tAnnotated Concept\tPattern Agreed') 77 | 78 | for mi_id in ref_mi_anno.occr.keys(): 79 | concept_id_gold = ref_mi_anno.occr[mi_id]['concept_id'] 80 | concept_id_target = target_mi_anno.occr[mi_id]['concept_id'] 81 | 82 | if concept_id_target is None: 83 | unannotated += 1 84 | continue 85 | 86 | mi = mi_info[mi_id] 87 | idf_hex, idf_var = mi['idf_hex'], mi['idf_var'] 88 | 89 | # for calculatin kappa 90 | idf_key = (idf_hex, idf_var) 91 | if idf_key not in labels.keys(): 92 | labels[idf_key] = ([concept_id_gold], [concept_id_target]) 93 | else: 94 | labels[idf_key][0].append(concept_id_gold) 95 | labels[idf_key][1].append(concept_id_target) 96 | 97 | # agreement 98 | if concept_id_target == concept_id_gold: 99 | pos += 1 100 | 101 | else: 102 | concept_list = ref_mcdict.concepts[idf_hex][idf_var] 103 | 104 | concept_gold = concept_list[concept_id_gold] 105 | concept_target = concept_list[concept_id_target] 106 | 107 | if concept_gold.affixes == concept_target.affixes: 108 | pattern_agreed = True 109 | else: 110 | pt_miss += 1 111 | pattern_agreed = False 112 | 113 | if show_mismatch: 114 | print( 115 | '{}\t{} ({})\t{} ({})\t{}'.format( 116 | mi_id, 117 | concept_id_gold, 118 | concept_gold.description, 119 | concept_id_target, 120 | concept_target.description, 121 | pattern_agreed, 122 | ) 123 | ) 124 | neg += 1 125 | 126 | # warn if annotation is incompleted 127 | if unannotated > 0: 128 | logger.warning('Found %d unannotated occurence(s).', unannotated) 129 | 130 | return pos, neg, pt_miss, labels 131 | 132 | 133 | def sog_match(ref_mi_anno, target_mi_anno, word_list): 134 | ref_sogs = [ 135 | ((word_list.index(sog[0]), word_list.index(sog[1])), anno['concept_id']) 136 | for anno in ref_mi_anno.occr.values() 137 | for sog in anno['sog'] 138 | ] 139 | target_sogs = [ 140 | ((word_list.index(sog[0]), word_list.index(sog[1])), anno['concept_id']) 141 | for anno in target_mi_anno.occr.values() 142 | for sog in anno['sog'] 143 | ] 144 | 145 | pos_sog_match = 0 146 | neg_sog_match = 0 147 | 148 | for ref_sog_tp in ref_sogs: 149 | ref_s, ref_e = ref_sog_tp[0] 150 | ref_concept = ref_sog_tp[1] 151 | 152 | for target_sog_tp in target_sogs: 153 | target_s, target_e = target_sog_tp[0] 154 | target_concept = target_sog_tp[1] 155 | 156 | if not (ref_e < target_s and ref_s < target_e) and not (ref_e > target_s and ref_s > target_e): 157 | if ref_concept == target_concept: 158 | pos_sog_match += 1 159 | else: 160 | neg_sog_match += 1 161 | 162 | return len(ref_sogs), len(target_sogs), pos_sog_match, neg_sog_match 163 | 164 | 165 | def main(): 166 | # parse options 167 | args = docopt(HELP, version=VERSION) 168 | 169 | main_logger.set_logger(args['--quiet'], args['--debug']) 170 | paper_id = args['ID'] 171 | show_mismatch = args['--show-mismatch'] 172 | 173 | # dirs and files 174 | if type(args['--target']) is not str: 175 | logger.critical('Option --target (-t) is required') 176 | exit(1) 177 | target_dir = Path(args['--target']) 178 | target_anno_json = target_dir / '{}_anno.json'.format(paper_id) 179 | target_mcdict_json = target_dir / '{}_mcdict.json'.format(paper_id) 180 | 181 | ref_dir = Path(args['--reference']) 182 | ref_anno_json = ref_dir / '{}_anno.json'.format(paper_id) 183 | ref_mcdict_json = ref_dir / '{}_mcdict.json'.format(paper_id) 184 | 185 | sources_dir = Path(args['--sources']) 186 | source_html = sources_dir / '{}.html'.format(paper_id) 187 | 188 | # load the target data 189 | target_mi_anno = MiAnno(target_anno_json) 190 | target_mcdict = McDict(target_mcdict_json) 191 | 192 | # load the reference data 193 | ref_mi_anno = MiAnno(ref_anno_json) 194 | ref_mcdict = McDict(ref_mcdict_json) 195 | 196 | # load the source HTML and extract information 197 | tree = lxml.html.parse(str(source_html)) 198 | mi_info, word_list = extract_info(tree) 199 | 200 | pos, neg, pt_miss, labels = calc_agreements(ref_mi_anno, target_mi_anno, ref_mcdict, mi_info, show_mismatch) 201 | 202 | nof_ref_sogs, nof_target_sogs, pos_sog_match, neg_sog_match = sog_match(ref_mi_anno, target_mi_anno, word_list) 203 | 204 | # show results 205 | total = pos + neg 206 | print('* Summary') 207 | print('Reference data: Annotation by {}, Math concept dict by {}'.format(ref_mi_anno.annotator, ref_mcdict.author)) 208 | print( 209 | 'Target data: Annotation by {}, Math concept dict by {}'.format(target_mi_anno.annotator, target_mcdict.author) 210 | ) 211 | print('Agreement: {}/{} = {:.2f}%'.format(pos, total, pos / total * 100)) 212 | if neg > 0: 213 | rate = pt_miss / neg * 100 214 | print('Pattern mismatches: {}/{} = {:.2f}%'.format(pt_miss, neg, rate)) 215 | 216 | print('* Source of grounding') 217 | print('#ref_sogs: {}'.format(nof_ref_sogs)) 218 | print('#target_sogs: {}'.format(nof_target_sogs)) 219 | print('#pos_sog_match: {}'.format(pos_sog_match)) 220 | print('#neg_sog_match: {}'.format(neg_sog_match)) 221 | 222 | print('* Kappas') 223 | kappas = [] 224 | for k, v in labels.items(): 225 | idf_hex, idf_var = k 226 | kappa = cohen_kappa_score(v[0], v[1]) 227 | count = len(v[0]) 228 | kappas.append((idf_hex, idf_var, kappa, count)) 229 | 230 | w_sum, w_cnt = 0, 0 231 | print('symbol\tvariation\tKappa\tcount') 232 | for res in sorted(kappas, key=lambda x: x[3], reverse=True): 233 | print(bytes.fromhex(res[0]).decode(), res[1], '{:.3f}'.format(res[2]), res[3], sep='\t') 234 | if not np.isnan(res[2]): 235 | w_cnt += res[3] 236 | w_sum += res[2] * res[3] 237 | print('Kappa (weighted avg.): %.3f' % (w_sum / w_cnt)) 238 | 239 | 240 | if __name__ == '__main__': 241 | main() 242 | -------------------------------------------------------------------------------- /tools/preprocess.py: -------------------------------------------------------------------------------- 1 | # The preprocess tool for MioGatto 2 | import lxml.html 3 | import unicodedata 4 | from docopt import docopt 5 | from pathlib import Path 6 | 7 | from lib.version import VERSION 8 | from lib.logger import main_logger 9 | from lib.util import get_mi2idf 10 | from lib.annotation import dump_json 11 | 12 | # meta 13 | PROG_NAME = "tools.preprocess" 14 | HELP = """Preprocess tool for MioGatto 15 | 16 | Usage: 17 | {p} [options] HTML 18 | 19 | Options: 20 | --embed-floats Preserve embed figure/table codes 21 | --overwrite Overwrite output files if already exist 22 | 23 | -d DIR, --data=DIR Dir for data outputs [default: ./templates] 24 | --sources=DIR Dir for HTML outputs [default: ./sources] 25 | 26 | -D, --debug Show debug messages 27 | -q, --quiet Show less messages 28 | 29 | -h, --help Show this screen and exit 30 | -V, --version Show version 31 | """.format( 32 | p=PROG_NAME 33 | ) 34 | 35 | logger = main_logger.getChild(PROG_NAME) 36 | 37 | 38 | def hex2surface(idf_hex): 39 | idf_text = bytes.fromhex(idf_hex).decode() 40 | surface = {'text': idf_text} 41 | 42 | if len(idf_text) < 2: 43 | surface['unicode_name'] = unicodedata.name(idf_text) 44 | 45 | return surface 46 | 47 | 48 | # add word span tags to text directly 49 | def split_words_into_span_tags(text, parent_id, idx): 50 | from lxml.html.builder import SPAN 51 | 52 | def word_span(w, p, i, c): 53 | s = SPAN(w) 54 | s.attrib['class'] = 'gd_word' 55 | s.attrib['id'] = '{}.{}.w{}'.format(p, i + 1, c) 56 | return s 57 | 58 | words = text.split(' ') 59 | word_cnt, spans = 1, [] 60 | 61 | for w in words[:-1]: 62 | spans.extend([word_span(w, parent_id, idx, word_cnt), SPAN(' ')]) 63 | word_cnt += 1 64 | 65 | if not words[-1] == '': 66 | spans.append(word_span(words[-1], parent_id, idx, word_cnt)) 67 | 68 | return spans 69 | 70 | 71 | def embed_word_span_tags(e, parent_id): 72 | # get texts and remove 73 | texts = [e.text] 74 | e.text = None 75 | for c in e.getchildren(): 76 | texts.append(c.tail) 77 | c.tail = None 78 | 79 | spans = [split_words_into_span_tags(t, parent_id, i) if t else None for i, t in enumerate(texts)] 80 | 81 | for i in range(len(spans) - 1, -1, -1): 82 | if not spans[i] is None: 83 | for s in reversed(spans[i]): 84 | e.insert(i, s) 85 | 86 | 87 | def remove_embed_floats(root, paper_id): 88 | # remove embed float 89 | from lxml.html.builder import IMG 90 | 91 | for e in root.xpath('//figure[@class="ltx_figure"]'): 92 | # remove embed figures 93 | for c in e: 94 | if c.tag != 'img' and c.tag != 'figcaption': 95 | e.remove(c) 96 | 97 | # add 98 | if [c.tag for c in e] == ['figcaption']: 99 | img = IMG() 100 | src = '/static/img/{}/{}.png'.format(paper_id, e.attrib['id'].replace('.', '_')) 101 | img.attrib['src'] = src 102 | img.attrib['alt'] = src 103 | e.insert(0, img) 104 | 105 | for e in root.xpath('//figure[@class="ltx_table"]'): 106 | # remove embed tables 107 | for c in e: 108 | if c.tag != 'figcaption': 109 | e.remove(c) 110 | 111 | # add 112 | img = IMG() 113 | src = '/static/img/{}/{}.png'.format(paper_id, e.attrib['id'].replace('.', '_')) 114 | img.attrib['src'] = src 115 | img.attrib['alt'] = src 116 | e.insert(0, img) 117 | 118 | 119 | def preprocess_html(tree, paper_id, embed_floats): 120 | root = tree.getroot() 121 | 122 | # drop unnecessary annotations 123 | for e in root.xpath('//annotation|//annotation-xml'): 124 | e.drop_tree() 125 | 126 | for e in root.xpath('//span[contains(@class,"ltx_text")]'): 127 | e.drop_tag() 128 | 129 | # tweak images 130 | for e in root.xpath('//img'): 131 | if 'ltx_graphics' in e.attrib.get('class', '').split(' '): 132 | src = '/static/img/{}/'.format(paper_id) + e.attrib['src'] 133 | e.attrib['src'] = src 134 | e.attrib['alt'] = src 135 | e.attrib['width'] = None 136 | e.attrib['height'] = None 137 | 138 | # normal paragraphs 139 | for e in root.xpath('//p'): 140 | parent_id = e.attrib['id'] 141 | embed_word_span_tags(e, parent_id) 142 | 143 | # captions 144 | for e in root.xpath('//figcaption'): 145 | parent_id = e.getparent().attrib['id'] 146 | embed_word_span_tags(e, parent_id) 147 | 148 | # footnotes 149 | for e in root.xpath('//span[contains(@class,"ltx_note_content")]'): 150 | parent_id = e.getparent().getparent().attrib['id'] 151 | embed_word_span_tags(e, parent_id) 152 | 153 | # paragraphs in inline blocks 154 | for e in root.xpath('//span[contains(@class,"ltx_inline-block")]//span[contains(@class, "ltx_p")]'): 155 | parent_id = e.attrib['id'] 156 | embed_word_span_tags(e, parent_id) 157 | 158 | # almost done 159 | if not embed_floats: 160 | remove_embed_floats(root, paper_id) 161 | 162 | 163 | def observe_mi(tree): 164 | # initialize 165 | identifiers = set() 166 | occurences = dict() 167 | mi_attribs = set() 168 | 169 | # the process 170 | mi2idf = get_mi2idf(tree) 171 | root = tree.getroot() 172 | 173 | for e in root.xpath('//mi'): 174 | # get mi_id and idf 175 | mi_id = e.attrib.get('id') 176 | idf = mi2idf.get(mi_id) 177 | 178 | if mi_id is None: 179 | # wired but to avoid errors 180 | continue 181 | 182 | if idf is not None: 183 | idf_hex = idf['idf_hex'] 184 | idf_var = idf['idf_var'] 185 | else: 186 | continue 187 | 188 | # check for the attrib 189 | mi_attribs.update(e.attrib) 190 | 191 | occurences[mi_id] = None 192 | 193 | identifiers.add((idf_hex, idf_var)) 194 | 195 | return occurences, identifiers, mi_attribs 196 | 197 | 198 | def idf2mc(idf_set): 199 | # initialize 200 | idf_dict = dict() 201 | 202 | # organize the identifiers 203 | for idf in idf_set: 204 | idf_hex, idf_var = idf 205 | if idf_hex not in idf_dict: 206 | idf_dict[idf_hex] = [idf_var] 207 | else: 208 | idf_dict[idf_hex].append(idf_var) 209 | 210 | idf_sorted = sorted(idf_dict.items(), key=lambda x: x[0]) 211 | 212 | # construct a list of grounding functions 213 | return {idf[0]: {'_surface': hex2surface(idf[0]), 'identifiers': {v: [] for v in idf[1]}} for idf in idf_sorted} 214 | 215 | 216 | def main(): 217 | # parse options 218 | args = docopt(HELP, version=VERSION) 219 | 220 | main_logger.set_logger(args['--quiet'], args['--debug']) 221 | embed_floats = args['--embed-floats'] 222 | 223 | # dirs and files 224 | data_dir = Path(args['--data']) 225 | sources_dir = Path(args['--sources']) 226 | 227 | html_in = Path(args['HTML']) 228 | paper_id = html_in.stem 229 | html_out = sources_dir / '{}.html'.format(paper_id) 230 | 231 | # now prepare for the preprocess 232 | logger.info('Begin to preprocess Paper "{}"'.format(paper_id)) 233 | 234 | data_dir.mkdir(parents=True, exist_ok=True) 235 | anno_json = data_dir / '{}_anno.json'.format(paper_id) 236 | mcdict_json = data_dir / '{}_mcdict.json'.format(paper_id) 237 | 238 | # prevent unintentional overwriting 239 | if args['--overwrite'] is not True: 240 | if html_out.exists(): 241 | logger.error('Source file %s exists. Use --overwrite to force', html_out) 242 | exit(1) 243 | 244 | if anno_json.exists() or mcdict_json.exists(): 245 | logger.error('Data files exist in %s. Use --overwrite to force', data_dir) 246 | exit(1) 247 | 248 | # load the HTML and modify the DOM tree 249 | tree = lxml.html.parse(str(html_in)) 250 | preprocess_html(tree, paper_id, embed_floats) 251 | 252 | # extract formulae information 253 | occurences, identifiers, attribs = observe_mi(tree) 254 | print('#indentifiers: {}'.format(len(identifiers))) 255 | print('#occurences: {}'.format(len(occurences))) 256 | print('mi attributes: {}'.format(', '.join(attribs))) 257 | 258 | # make the annotation structure 259 | mi_anno = { 260 | mi_id: { 261 | 'concept_id': concept_id, 262 | 'sog': [], 263 | } 264 | for mi_id, concept_id in occurences.items() 265 | } 266 | 267 | # write output files 268 | logger.info('Writing preprocessed HTML to %s', html_out) 269 | tree.write(str(html_out), pretty_print=True, encoding='utf-8') 270 | 271 | logger.info('Writing initialized anno template to %s', anno_json) 272 | with open(anno_json, 'w') as f: 273 | dump_json( 274 | { 275 | '_anno_version': '1.0', 276 | '_annotator': 'YOUR NAME', 277 | 'mi_anno': mi_anno, 278 | }, 279 | f, 280 | ) 281 | 282 | logger.info('Writing initialized mcdict template to %s', mcdict_json) 283 | with open(mcdict_json, 'w') as f: 284 | dump_json( 285 | { 286 | '_author': 'YOUR NAME', 287 | '_mcdict_version': '1.0', 288 | 'concepts': idf2mc(identifiers), 289 | }, 290 | f, 291 | ) 292 | 293 | 294 | if __name__ == '__main__': 295 | main() 296 | -------------------------------------------------------------------------------- /tools/analyzer.py: -------------------------------------------------------------------------------- 1 | # The analyzer tool for MioGatto 2 | import itertools 3 | import lxml.html 4 | import numpy as np 5 | import seaborn as sns 6 | import matplotlib.pyplot as plt 7 | from docopt import docopt 8 | from pathlib import Path 9 | 10 | from lib.version import VERSION 11 | from lib.logger import main_logger 12 | from lib.util import get_mi2idf 13 | from lib.annotation import MiAnno, McDict 14 | 15 | # meta 16 | PROG_NAME = "tools.analyzer" 17 | HELP = """Analysing tool for MioGatto 18 | 19 | Usage: 20 | {p} [options] ID 21 | 22 | Options: 23 | -o DIR, --out=DIR Dir to save results 24 | -d DIR, --data=DIR Dir for the gold data [default: ./data] 25 | --sources=DIR Dir for preprocessed HTML [default: ./sources] 26 | 27 | -D, --debug Show debug messages 28 | -q, --quiet Show less messages 29 | 30 | -h, --help Show this screen and exit 31 | -V, --version Show version 32 | """.format( 33 | p=PROG_NAME 34 | ) 35 | 36 | logger = main_logger.getChild(PROG_NAME) 37 | 38 | 39 | def extract_info(tree, mi2idf): 40 | root = tree.getroot() 41 | html_str = lxml.html.tostring(tree, encoding='utf-8').decode('utf-8') 42 | 43 | # extract mi info 44 | mi_info = dict() 45 | for e in root.xpath('//mi'): 46 | mi_id = e.attrib.get('id') 47 | 48 | # idf info 49 | idf = mi2idf.get(mi_id) 50 | 51 | if idf is not None: 52 | mi_info[mi_id] = idf 53 | else: 54 | continue 55 | 56 | # position info 57 | pos = html_str.find(lxml.html.tostring(e, encoding='utf-8').decode('utf-8')) 58 | mi_info[mi_id]['pos'] = pos 59 | 60 | # extract section info 61 | sec_info = dict() 62 | for e in root.xpath('//section'): 63 | sec_id = e.attrib.get('id') 64 | pos = html_str.find(lxml.html.tostring(e, encoding='utf-8').decode('utf-8')) 65 | sec_info[sec_id] = pos 66 | 67 | logger.debug('{sec_info=}') 68 | 69 | return mi_info, sec_info 70 | 71 | 72 | def analyze_annotation(paper_id, tree, mi_anno, mcdict, mi_info, mi2idf): 73 | concepts = mcdict.concepts 74 | 75 | # basic analysis for mcdict 76 | nof_idf = 0 77 | nof_idf_mul = 0 78 | nof_concept = 0 79 | 80 | for letter in concepts.values(): 81 | nof_idf += len(letter) 82 | 83 | for idf in letter.values(): 84 | if len(idf) > 1: 85 | nof_idf_mul += 1 86 | nof_concept += len(idf) 87 | 88 | root = tree.getroot() 89 | nof_words = len(root.xpath('//span[@class = "gd_word"]')) 90 | 91 | print('* Basic information') 92 | print('Paper ID: {}'.format(paper_id)) 93 | print('#words: {}'.format(nof_words)) 94 | print('Author of math concept dict: {}'.format(mcdict.author)) 95 | print('Annotator: {}'.format(mi_anno.annotator)) 96 | print('#types of identifiers: {}'.format(len(concepts))) 97 | print('#occurences: {}'.format(len(mi_anno.occr))) 98 | print() 99 | 100 | # analyse items 101 | items = sorted( 102 | [ 103 | (mcdict.surfaces[idf_hex]['text'], idf_var, len(idf)) 104 | for idf_hex, v in concepts.items() 105 | for idf_var, idf in v.items() 106 | ], 107 | key=lambda x: x[2], 108 | reverse=True, 109 | ) 110 | logger.debug(f'{items=}') 111 | nof_items = np.array([i[2] for i in items]) 112 | 113 | print('* Math concept dictionary') 114 | print('#entries (identifiers): {}'.format(nof_idf)) 115 | print('#items (math concepts): {}'.format(nof_concept)) 116 | print('#entries with multiple items: {}'.format(nof_idf_mul)) 117 | print() 118 | 119 | print('* Number of items in each entry') 120 | print('Max: {}'.format(nof_items[0])) 121 | print('Median: {}'.format(int(np.median(nof_items)))) 122 | print('Mean: {:.1f}'.format(np.mean(nof_items))) 123 | print('Variance: {:.1f}'.format(np.var(nof_items))) 124 | print('Standard deviation: {:.1f}'.format(np.std(nof_items))) 125 | print() 126 | 127 | # analyze occurences 128 | cnt_iter = itertools.count(0) 129 | 130 | concept_dict = dict() 131 | for idf_hex, v in concepts.items(): 132 | concept_dict[idf_hex] = dict() 133 | for idf_var, idf in v.items(): 134 | concept_dict[idf_hex][idf_var] = [ 135 | {'sid': next(cnt_iter), 'count': 0} for _ in idf # unique ID, number of occurences 136 | ] 137 | 138 | nof_annotated, total_nof_candidates, nof_sog = 0, 0, 0 139 | candidates = [0] * nof_items[0] 140 | occurences = [] 141 | for mi_id, anno in mi_anno.occr.items(): 142 | mi = mi_info.get(mi_id, None) 143 | if mi is None: 144 | continue 145 | idf_hex, idf_var = mi['idf_hex'], mi['idf_var'] 146 | 147 | nof_sog += len(anno.get('sog', [])) 148 | 149 | nof_candidates = len(concept_dict[idf_hex][idf_var]) 150 | candidates[nof_candidates - 1] += 1 151 | total_nof_candidates += nof_candidates 152 | 153 | concept_id = anno.get('concept_id') 154 | if concept_id is not None: 155 | nof_annotated += 1 156 | 157 | concept_sid = concept_dict[idf_hex][idf_var][concept_id]['sid'] 158 | concept_dict[idf_hex][idf_var][concept_id]['count'] += 1 159 | occurences.append((concept_sid, mi['pos'])) 160 | 161 | print('* Annotation') 162 | nof_occurences = len(mi_anno.occr) 163 | progress_rate = nof_annotated / nof_occurences * 100 164 | print('Progress rate: {:.2f}% ({}/{})'.format(progress_rate, nof_annotated, nof_occurences)) 165 | print('Average #candidates: {:.1f}'.format(total_nof_candidates / nof_occurences)) 166 | print('#SoG: {}'.format(nof_sog)) 167 | print() 168 | 169 | print('* Number of occurences by concept') 170 | counts, count_zeros = [], [] 171 | for idf_hex, v in concept_dict.items(): 172 | for idf_var, cls in v.items(): 173 | for cid, c in enumerate(cls): 174 | cnt = c['count'] 175 | if cnt == 0: 176 | # do not consider if no occurence is associated 177 | # this will be warned afterwards 178 | count_zeros.append((idf_hex, idf_var, cid)) 179 | else: 180 | counts.append(cnt) 181 | 182 | print('Max: {}'.format(max(counts))) 183 | print('Median: {}'.format(int(np.median(counts)))) 184 | print('Mean: {:.1f}'.format(np.mean(counts))) 185 | print('Variance: {:.1f}'.format(np.var(counts))) 186 | print('Standard deviation: {:.1f}'.format(np.std(counts))) 187 | print() 188 | 189 | # warnings 190 | if len(count_zeros) > 0: 191 | logger.warning('Nothing is associated with the following concepts:') 192 | for tp in count_zeros: 193 | idf_hex, idf_var, cid = tp 194 | surface = mcdict.surfaces[idf_hex]['text'] 195 | desc = concepts[idf_hex][idf_var][cid].description 196 | logger.warning(' %s > %s > %d (%s)', surface, idf_var, cid, desc) 197 | 198 | # output for debugging 199 | logger.debug(f'{concept_dict=}') 200 | logger.debug(f'{occurences=}') 201 | logger.debug(f'{candidates=}') 202 | 203 | return items, concept_dict, occurences 204 | 205 | 206 | def export_graphs(paper_id, items, concept_dict, occurences, sec_info, out_dir): 207 | out_dir.mkdir(parents=True, exist_ok=True) 208 | tex_paper_id = paper_id.replace('.', '_') 209 | 210 | # export items data 211 | items_tex = out_dir / '{}_items.tex'.format(tex_paper_id) 212 | with open(items_tex, 'w') as f: 213 | for i in items: 214 | f.write('(\\gf{{{}}}{{{}}}, {})\n'.format(i[0], i[1], i[2])) 215 | 216 | # plot items 217 | sns.set_style("whitegrid", {'axes.grid': False}) 218 | plt.tick_params(labelbottom=False) 219 | plt.bar([i[0] for i in items], [i[2] for i in items]) 220 | 221 | items_png = str(out_dir / '{}_items.png'.format(paper_id)) 222 | plt.savefig(items_png) 223 | plt.clf() 224 | 225 | # export occurences data 226 | occurences_dat = out_dir / '{}_occurences.dat'.format(tex_paper_id) 227 | with open(occurences_dat, 'w') as f: 228 | for p in occurences: 229 | f.write('{} {}\n'.format(p[0] + 0.5, p[1])) 230 | 231 | sections_tex = out_dir / '{}_sections.tex'.format(tex_paper_id) 232 | s0 = r'\addplot [domain=-2:106, dashed] {{{}}} ' r'node [pos=0, left] {{\S{}}};' 233 | with open(sections_tex, 'w') as f: 234 | for sec, pos in sec_info.items(): 235 | f.write(s0.format(pos, sec.replace('S', '')) + '\r') 236 | 237 | identifiers_tex = out_dir / '{}_identifiers.tex'.format(tex_paper_id) 238 | s1 = r'\addplot [black] coordinates {{({x}, -41900) ({x}, 420000)}};' 239 | with open(identifiers_tex, 'w') as f: 240 | x = 0 241 | for dc in concept_dict.values(): 242 | for ls in dc.values(): 243 | x += len(ls) 244 | f.write(s1.format(x=x) + '\n') 245 | 246 | # plot occurences 247 | plt.scatter([v[0] for v in occurences], [v[1] for v in occurences], s=2) 248 | plt.xlabel('Concepts') 249 | plt.ylabel('Position') 250 | 251 | occurences_png = str(out_dir / '{}_occurences.png'.format(paper_id)) 252 | plt.savefig(occurences_png) 253 | plt.clf() 254 | 255 | 256 | def main(): 257 | # parse options 258 | args = docopt(HELP, version=VERSION) 259 | 260 | main_logger.set_logger(args['--quiet'], args['--debug']) 261 | paper_id = args['ID'] 262 | 263 | # dirs and files 264 | data_dir = Path(args['--data']) 265 | 266 | sources_dir = Path(args['--sources']) 267 | source_html = sources_dir / '{}.html'.format(paper_id) 268 | 269 | anno_json = data_dir / '{}_anno.json'.format(paper_id) 270 | mcdict_json = data_dir / '{}_mcdict.json'.format(paper_id) 271 | 272 | # load the data 273 | mi_anno = MiAnno(anno_json) 274 | mcdict = McDict(mcdict_json) 275 | 276 | # load the source HTML and extract information 277 | tree = lxml.html.parse(str(source_html)) 278 | mi2idf = get_mi2idf(tree) 279 | mi_info, sec_info = extract_info(tree, mi2idf) 280 | 281 | items, concept_dict, occurences = analyze_annotation(paper_id, tree, mi_anno, mcdict, mi_info, mi2idf) 282 | 283 | # supplementary graphs 284 | if args['--out'] is not None: 285 | out_dir = Path(args['--out']) 286 | export_graphs(paper_id, items, concept_dict, occurences, sec_info, out_dir) 287 | 288 | 289 | if __name__ == '__main__': 290 | main() 291 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/jquery-ui.theme.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2016-09-14 2 | * http://jqueryui.com 3 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 4 | 5 | .ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;filter:Alpha(Opacity=70);font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;filter:Alpha(Opacity=35);background-image:none}.ui-state-disabled .ui-icon{filter:Alpha(Opacity=35)}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank{background-position:16px 16px}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} -------------------------------------------------------------------------------- /static/index.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";function t(t){return t.replace(/[ !"#$%&'()*+,.\/:;<=>?@\[\\\]^`{|}~]/g,"\\$&")}function e(t){let e={};var o;e.hex=(o=t.text(),Array.from((new TextEncoder).encode(o)).map((t=>t.toString(16))).join("")),e.var="default";let n=t.attr("mathvariant");null!=n&&(e.var="normal"==n?"roman":n);let i=t.data("math-concept");return null!=i&&(e.concept=Number(i)),e}function o(t){return null!=t.concept?c[t.hex][t.var][t.concept]:void 0}function n(t){if(null!=c[t.hex])return c[t.hex][t.var]}function i(t){let o=[];t.is("mi")&&null!=n(e(t))&&(o=[t]);for(let e=0;e0&&(e=t.affixes.join(", ")),`${t.description} [${e}] (arity: ${t.arity})`}return"(No description)"},open:function(t,e){$("mi").each((function(){u($(this))}))}})})),$((function(){function o(o){o.attr("style","border: dotted 2px #000000; padding: 10px;");let a=e(o),d=n(a),s=o.attr("id");if(null!=d&&null!=s)if(d.length>0)!function(o,n,a){let d=``,s="";for(let t in a){let e=a[t],i=``,l="NONE";e.affixes.length>0&&(l=e.affixes.join(", ")),s+=`${i}`}let r=`

ID: ${o}


${d+`
${s}

`}

`,p=$("#anno-box");p.html(r),$("button#assign-concept").button(),$("button#assign-concept").on("click",(function(){let e=p.find(`#form-${t(o)}`);if(!($(`#form-${t(o)} input:checked`).length>0))return alert("Please select a concept."),!1;localStorage.scroll_top=$(window).scrollTop(),e.attr("action","/_concept"),e.append(``),e.trigger("submit")})),$("button#remove-concept").button(),$("button#remove-concept").on("click",(function(){let e=p.find(`#form-${t(o)}`);e.attr("action","/_remove_concept"),e.append(``),e.trigger("submit")})),i(n),$("a.edit-concept").on("click",(function(){let o=$(this).attr("data-mi"),n=$(this).attr("data-concept");null!=o&&null!=n&&function(t,e){let o=$("#concept-dialog-template").clone();o.removeAttr("id");let n=o.find("#concept-form");n.attr("action","/_update_concept");let i=c[t.hex][t.var][e];n.find("textarea").text(i.description),n.find('input[name="arity"]').attr("value",i.arity),i.affixes.forEach((function(t,e){n.find(`select[name="affixes${e}"]`).find(`option[value="${t}"]`).prop("selected",!0)})),o.dialog({modal:!0,title:"Edit Concept",width:500,buttons:{OK:function(){localStorage.scroll_top=$(window).scrollTop(),n.append(``),n.append(``),n.append(``),n.append(``),n.trigger("submit")},Cancel:function(){$(this).dialog("close")}}})}(e($("#"+t(o))),Number(n))})),$("mi").each((function(){u($(this))}))}(s,a,d);else{let t=`

ID: ${s}


No concept is available.

`;$("#anno-box").html(t),i(a)}}function i(t){$("button#new-concept").button(),$("button#new-concept").on("click",(function(){let e=$("#concept-dialog-template").clone();e.attr("id","concept-dialog"),e.removeClass("concept-dialog");let o=e.find("#concept-form");o.attr("action","/_new_concept"),e.dialog({modal:!0,title:"New Concept",width:500,buttons:{OK:function(){localStorage.scroll_top=$(window).scrollTop(),o.append(``),o.append(``),o.append(``),o.trigger("submit")},Cancel:function(){$(this).dialog("close")}},close:function(){$(this).remove()}})}))}$("mi").on("click",(function(){let e=sessionStorage.getItem("mi_id");null!=e&&$("#"+t(e)).removeAttr("style"),sessionStorage.mi_id=$(this).attr("id"),o($(this)),"true"==localStorage["option-limited-highlight"]&&(r.limited_highlight=!0),f()})),$(window).scrollTop(localStorage.scroll_top);let a=sessionStorage.mi_id;null!=a&&o($("#"+t(a)))})),$((function(){let n,i;$(document).on("mouseup",(function(c){n=c.pageX,i=c.pageY,$(".sog-menu").css("display","none");let[a,d,s]=function(){var t,e,o,n;let i;if(window.getSelection?i=window.getSelection():document.getSelection&&(i=document.getSelection()),null==i||"Range"!=i.type)return[void 0,void 0,void 0];let l=null===(t=null==i?void 0:i.anchorNode)||void 0===t?void 0:t.parentElement,c=null===(e=null==i?void 0:i.focusNode)||void 0===e?void 0:e.parentElement;if(null==l||null==c)return[void 0,void 0,void 0];if(0==$(l).parents(".main").length||0==$(c).parents(".main").length)return[void 0,void 0,void 0];let a,d,s,r,u=l.getBoundingClientRect(),p=c.getBoundingClientRect();return u.topSelected mi: ${u}

`;$(".sog-add-menu-info").html(p),$(".sog-menu .sog-add").off("click"),$(".sog-menu .sog-add").on("click",(function(){$(".sog-menu").css("display","none");let t={mcdict_edit_id:l,mi_id:u,start_id:a,stop_id:d};localStorage.scroll_top=$(window).scrollTop(),$.when($.post("/_add_sog",t)).done((function(){location.reload()})).fail((function(){console.error("Failed to POST _add_sog!")}))}));let g=s.getAttribute("data-sog-mi"),f=Number(s.getAttribute("data-sog-type")),m=s.getAttribute("data-sog-start"),h=s.getAttribute("data-sog-stop"),_=!0;if(r.limited_highlight&&null!=u&&null!=g){let o=e($("#"+t(u))),n=e($("#"+t(g)));o.hex==n.hex&&o.var==n.var||(_=!1)}null!=(null==s?void 0:s.getAttribute("data-sog-mi"))&&_?$(".sog-mod-menu").css("display","inherit"):$(".sog-mod-menu").css("display","none");let v="unknown";0==f?v="declaration":1==f?v="definition":2==f&&(v="others");let b=`

SoG for ${g}
Type: ${v}

`;$(".sog-mod-menu-info").html(b),$(".sog-menu .sog-type").off("click"),$(".sog-menu .sog-type").on("click",(function(){if($(".sog-menu").css("display","none"),null==s)return;let t=$("#sog-type-dialog-template").clone();t.attr("id","sog-type-dialog"),t.removeClass("sog-type-dialog");let e=t.find("#sog-type-form");e.attr("action","/_change_sog_type"),t.find(`input[value="${f}"]`).prop("checked",!0),t.dialog({modal:!0,title:"Change SoG Type",width:200,buttons:{OK:function(){localStorage.scroll_top=$(window).scrollTop(),e.append(``),e.append(``),e.append(``),e.append(``),e.trigger("submit")},Cancel:function(){$(this).dialog("close")}},close:function(){$(this).remove()}})})),$(".sog-menu .sog-del").off("click"),$(".sog-menu .sog-del").on("click",(function(){if($(".sog-menu").css("display","none"),null==s)return;let t={mcdict_edit_id:l,mi_id:s.getAttribute("data-sog-mi"),start_id:s.getAttribute("data-sog-start"),stop_id:s.getAttribute("data-sog-stop")};localStorage.scroll_top=$(window).scrollTop(),$.when($.post("/_delete_sog",t)).done((function(){location.reload()})).fail((function(){console.error("Failed to POST _delete_sog!")}))}))}))})),$((function(){$("mi").each((function(){!function(t){let o=n(e(t));null==t.data("math-concept")&&null!=o&&t.attr("mathbackground","#D3D3D3")}($(this))}))}));for(let t=1;t<10;t++)$(document).on("keydown",(function(e){var o;$("#concept-dialog")[0]||e.key==t.toString(10)&&(o=t,$("#c"+(o-1))[0]&&($('input[name="concept"]').prop("checked",!1),$("#c"+(o-1)).prop("checked",!0)))}));$(document).on("keydown",(function(t){"Enter"==t.key&&($("#concept-dialog")[0]||$("#assign-concept").trigger("click"))})),$(document).on("keydown",(function(t){"j"==t.key?$("button#jump-to-next-unannotated-mi").trigger("click"):"k"==t.key&&$("button#jump-to-prev-unannotated-mi").trigger("click")}));let m=[],h={};$((function(){m=i($(":root"));for(let t=0;t0;n--){let i=(t+n)%m.length;if(null==o(e(m[i])))return i}}((n+m.length-1)%m.length);if(null!=i){let e=m[i],o=null===(t=null==e?void 0:e.offset())||void 0===t?void 0:t.top,n=$(window).height();null!=o&&null!=n&&($(window).scrollTop(o-n/2),e.trigger("click"))}}))})),$((function(){$("button#back-to-selected-mi").button(),$("button#back-to-selected-mi").on("click",(function(){var e;if(null!=sessionStorage.mi_id){let o=$("#"+t(sessionStorage.mi_id)),n=null===(e=null==o?void 0:o.offset())||void 0===e?void 0:e.top,i=$(window).height();null!=n&&null!=i&&$(window).scrollTop(n-i/2)}}))})),$((function(){$("button#edit-mcdict").button(),$("button#edit-mcdict").on("click",(function(){let t=$("#edit-mcdict-form");t.attr("action","/edit_mcdict"),t.trigger("submit")}))})),$((function(){$(window).scrollTop(localStorage.scroll_top)}))})(); -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/AUTHORS.txt: -------------------------------------------------------------------------------- 1 | Authors ordered by first contribution 2 | A list of current team members is available at http://jqueryui.com/about 3 | 4 | Paul Bakaus 5 | Richard Worth 6 | Yehuda Katz 7 | Sean Catchpole 8 | John Resig 9 | Tane Piper 10 | Dmitri Gaskin 11 | Klaus Hartl 12 | Stefan Petre 13 | Gilles van den Hoven 14 | Micheil Bryan Smith 15 | Jörn Zaefferer 16 | Marc Grabanski 17 | Keith Wood 18 | Brandon Aaron 19 | Scott González 20 | Eduardo Lundgren 21 | Aaron Eisenberger 22 | Joan Piedra 23 | Bruno Basto 24 | Remy Sharp 25 | Bohdan Ganicky 26 | David Bolter 27 | Chi Cheng 28 | Ca-Phun Ung 29 | Ariel Flesler 30 | Maggie Wachs 31 | Scott Jehl 32 | Todd Parker 33 | Andrew Powell 34 | Brant Burnett 35 | Douglas Neiner 36 | Paul Irish 37 | Ralph Whitbeck 38 | Thibault Duplessis 39 | Dominique Vincent 40 | Jack Hsu 41 | Adam Sontag 42 | Carl Fürstenberg 43 | Kevin Dalman 44 | Alberto Fernández Capel 45 | Jacek Jędrzejewski (http://jacek.jedrzejewski.name) 46 | Ting Kuei 47 | Samuel Cormier-Iijima 48 | Jon Palmer 49 | Ben Hollis 50 | Justin MacCarthy 51 | Eyal Kobrigo 52 | Tiago Freire 53 | Diego Tres 54 | Holger Rüprich 55 | Ziling Zhao 56 | Mike Alsup 57 | Robson Braga Araujo 58 | Pierre-Henri Ausseil 59 | Christopher McCulloh 60 | Andrew Newcomb 61 | Lim Chee Aun 62 | Jorge Barreiro 63 | Daniel Steigerwald 64 | John Firebaugh 65 | John Enters 66 | Andrey Kapitcyn 67 | Dmitry Petrov 68 | Eric Hynds 69 | Chairat Sunthornwiphat 70 | Josh Varner 71 | Stéphane Raimbault 72 | Jay Merrifield 73 | J. Ryan Stinnett 74 | Peter Heiberg 75 | Alex Dovenmuehle 76 | Jamie Gegerson 77 | Raymond Schwartz 78 | Phillip Barnes 79 | Kyle Wilkinson 80 | Khaled AlHourani 81 | Marian Rudzynski 82 | Jean-Francois Remy 83 | Doug Blood 84 | Filippo Cavallarin 85 | Heiko Henning 86 | Aliaksandr Rahalevich 87 | Mario Visic 88 | Xavi Ramirez 89 | Max Schnur 90 | Saji Nediyanchath 91 | Corey Frang 92 | Aaron Peterson 93 | Ivan Peters 94 | Mohamed Cherif Bouchelaghem 95 | Marcos Sousa 96 | Michael DellaNoce 97 | George Marshall 98 | Tobias Brunner 99 | Martin Solli 100 | David Petersen 101 | Dan Heberden 102 | William Kevin Manire 103 | Gilmore Davidson 104 | Michael Wu 105 | Adam Parod 106 | Guillaume Gautreau 107 | Marcel Toele 108 | Dan Streetman 109 | Matt Hoskins 110 | Giovanni Giacobbi 111 | Kyle Florence 112 | Pavol Hluchý 113 | Hans Hillen 114 | Mark Johnson 115 | Trey Hunner 116 | Shane Whittet 117 | Edward A Faulkner 118 | Adam Baratz 119 | Kato Kazuyoshi 120 | Eike Send 121 | Kris Borchers 122 | Eddie Monge 123 | Israel Tsadok 124 | Carson McDonald 125 | Jason Davies 126 | Garrison Locke 127 | David Murdoch 128 | Benjamin Scott Boyle 129 | Jesse Baird 130 | Jonathan Vingiano 131 | Dylan Just 132 | Hiroshi Tomita 133 | Glenn Goodrich 134 | Tarafder Ashek-E-Elahi 135 | Ryan Neufeld 136 | Marc Neuwirth 137 | Philip Graham 138 | Benjamin Sterling 139 | Wesley Walser 140 | Kouhei Sutou 141 | Karl Kirch 142 | Chris Kelly 143 | Jason Oster 144 | Felix Nagel 145 | Alexander Polomoshnov 146 | David Leal 147 | Igor Milla 148 | Dave Methvin 149 | Florian Gutmann 150 | Marwan Al Jubeh 151 | Milan Broum 152 | Sebastian Sauer 153 | Gaëtan Muller 154 | Michel Weimerskirch 155 | William Griffiths 156 | Stojce Slavkovski 157 | David Soms 158 | David De Sloovere 159 | Michael P. Jung 160 | Shannon Pekary 161 | Dan Wellman 162 | Matthew Edward Hutton 163 | James Khoury 164 | Rob Loach 165 | Alberto Monteiro 166 | Alex Rhea 167 | Krzysztof Rosiński 168 | Ryan Olton 169 | Genie <386@mail.com> 170 | Rick Waldron 171 | Ian Simpson 172 | Lev Kitsis 173 | TJ VanToll 174 | Justin Domnitz 175 | Douglas Cerna 176 | Bert ter Heide 177 | Jasvir Nagra 178 | Yuriy Khabarov <13real008@gmail.com> 179 | Harri Kilpiö 180 | Lado Lomidze 181 | Amir E. Aharoni 182 | Simon Sattes 183 | Jo Liss 184 | Guntupalli Karunakar 185 | Shahyar Ghobadpour 186 | Lukasz Lipinski 187 | Timo Tijhof 188 | Jason Moon 189 | Martin Frost 190 | Eneko Illarramendi 191 | EungJun Yi 192 | Courtland Allen 193 | Viktar Varvanovich 194 | Danny Trunk 195 | Pavel Stetina 196 | Michael Stay 197 | Steven Roussey 198 | Michael Hollis 199 | Lee Rowlands 200 | Timmy Willison 201 | Karl Swedberg 202 | Baoju Yuan 203 | Maciej Mroziński 204 | Luis Dalmolin 205 | Mark Aaron Shirley 206 | Martin Hoch 207 | Jiayi Yang 208 | Philipp Benjamin Köppchen 209 | Sindre Sorhus 210 | Bernhard Sirlinger 211 | Jared A. Scheel 212 | Rafael Xavier de Souza 213 | John Chen 214 | Robert Beuligmann 215 | Dale Kocian 216 | Mike Sherov 217 | Andrew Couch 218 | Marc-Andre Lafortune 219 | Nate Eagle 220 | David Souther 221 | Mathias Stenbom 222 | Sergey Kartashov 223 | Avinash R 224 | Ethan Romba 225 | Cory Gackenheimer 226 | Juan Pablo Kaniefsky 227 | Roman Salnikov 228 | Anika Henke 229 | Samuel Bovée 230 | Fabrício Matté 231 | Viktor Kojouharov 232 | Pawel Maruszczyk (http://hrabstwo.net) 233 | Pavel Selitskas 234 | Bjørn Johansen 235 | Matthieu Penant 236 | Dominic Barnes 237 | David Sullivan 238 | Thomas Jaggi 239 | Vahid Sohrabloo 240 | Travis Carden 241 | Bruno M. Custódio 242 | Nathanael Silverman 243 | Christian Wenz 244 | Steve Urmston 245 | Zaven Muradyan 246 | Woody Gilk 247 | Zbigniew Motyka 248 | Suhail Alkowaileet 249 | Toshi MARUYAMA 250 | David Hansen 251 | Brian Grinstead 252 | Christian Klammer 253 | Steven Luscher 254 | Gan Eng Chin 255 | Gabriel Schulhof 256 | Alexander Schmitz 257 | Vilhjálmur Skúlason 258 | Siebrand Mazeland 259 | Mohsen Ekhtiari 260 | Pere Orga 261 | Jasper de Groot 262 | Stephane Deschamps 263 | Jyoti Deka 264 | Andrei Picus 265 | Ondrej Novy 266 | Jacob McCutcheon 267 | Monika Piotrowicz 268 | Imants Horsts 269 | Eric Dahl 270 | Dave Stein 271 | Dylan Barrell 272 | Daniel DeGroff 273 | Michael Wiencek 274 | Thomas Meyer 275 | Ruslan Yakhyaev 276 | Brian J. Dowling 277 | Ben Higgins 278 | Yermo Lamers 279 | Patrick Stapleton 280 | Trisha Crowley 281 | Usman Akeju 282 | Rodrigo Menezes 283 | Jacques Perrault 284 | Frederik Elvhage 285 | Will Holley 286 | Uri Gilad 287 | Richard Gibson 288 | Simen Bekkhus 289 | Chen Eshchar 290 | Bruno Pérel 291 | Mohammed Alshehri 292 | Lisa Seacat DeLuca 293 | Anne-Gaelle Colom 294 | Adam Foster 295 | Luke Page 296 | Daniel Owens 297 | Michael Orchard 298 | Marcus Warren 299 | Nils Heuermann 300 | Marco Ziech 301 | Patricia Juarez 302 | Ben Mosher 303 | Ablay Keldibek 304 | Thomas Applencourt 305 | Jiabao Wu 306 | Eric Lee Carraway 307 | Victor Homyakov 308 | Myeongjin Lee 309 | Liran Sharir 310 | Weston Ruter 311 | Mani Mishra 312 | Hannah Methvin 313 | Leonardo Balter 314 | Benjamin Albert 315 | Michał Gołębiowski 316 | Alyosha Pushak 317 | Fahad Ahmad 318 | Matt Brundage 319 | Francesc Baeta 320 | Piotr Baran 321 | Mukul Hase 322 | Konstantin Dinev 323 | Rand Scullard 324 | Dan Strohl 325 | Maksim Ryzhikov 326 | Amine HADDAD 327 | Amanpreet Singh 328 | Alexey Balchunas 329 | Peter Kehl 330 | Peter Dave Hello 331 | Johannes Schäfer 332 | Ville Skyttä 333 | Ryan Oriecuia 334 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/jquery-ui.structure.min.css: -------------------------------------------------------------------------------- 1 | /*! jQuery UI - v1.12.1 - 2016-09-14 2 | * http://jqueryui.com 3 | * Copyright jQuery Foundation and other contributors; Licensed MIT */ 4 | 5 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;filter:Alpha(Opacity=0)}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;filter:alpha(opacity=25);opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:default;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px} -------------------------------------------------------------------------------- /server/miogatto.py: -------------------------------------------------------------------------------- 1 | # The server implementation for MioGatto 2 | from flask import request, redirect, flash, render_template, Markup 3 | from typing import Optional 4 | from logging import Logger 5 | from copy import deepcopy 6 | from lxml import etree 7 | import subprocess 8 | import json 9 | import re 10 | 11 | from lib.version import VERSION 12 | from lib.annotation import MiAnno, McDict 13 | from lib.datatypes import MathConcept 14 | 15 | # get git revision 16 | try: 17 | GIT_REVISON = subprocess.check_output(['git', 'rev-parse', '--short', 'HEAD']).strip().decode('ascii') 18 | except OSError: 19 | GIT_REVISON = 'Unknown' 20 | 21 | 22 | def make_concept(res) -> Optional[MathConcept]: 23 | # check arity 24 | if not res.get('arity').isdigit(): 25 | flash('Arity must be non-negative integer.') 26 | return None 27 | else: 28 | arity = int(res.get('arity')) 29 | 30 | # check description 31 | description = res.get('description') 32 | if len(description) == 0: 33 | flash('Description must be filled.') 34 | return None 35 | 36 | # get affixes 37 | affixes = [] 38 | for i in range(10): 39 | t_i = res.get('affixes{}'.format(i)) 40 | if t_i != '': 41 | affixes.append(t_i) 42 | 43 | return MathConcept(description, arity, affixes) 44 | 45 | 46 | def affixes_pulldowns(): 47 | select_tag = '''
  • ''' 78 | items = '\n'.join([select_tag.format(i) for i in range(10)]) 79 | 80 | return '
      {}
    '.format(items) 81 | 82 | 83 | def preprocess_mcdict(concepts): 84 | # description processor 85 | def process_math(math): 86 | def construct_mi(idf_text, idf_var, concept_id): 87 | mi = '' 95 | 96 | return mi 97 | 98 | # protect references (@x) 99 | math = re.sub(r'(@\d+)', r'\1', math) 100 | 101 | # expand \gf 102 | rls = [ 103 | (construct_mi(m.group(1), m.group(2), int(m.group(3))), m.span()) 104 | for m in re.finditer(r'\\gf{(.*?)}{(.*?)}{(\d*?)}', math) 105 | ] 106 | for r in reversed(rls): 107 | s, e = r[1] 108 | math = math[:s] + r[0] + math[e:] 109 | 110 | return '' + math + '' 111 | 112 | def process_desc(desc): 113 | if not desc or '$' not in desc: 114 | return desc 115 | 116 | # process maths 117 | it = desc.split('$') 118 | desc_new = ''.join([a + process_math(b) for a, b in zip(it[::2], it[1::2])]) 119 | if len(it) % 2 != 0: 120 | desc_new += it[-1] 121 | 122 | return desc_new 123 | 124 | # initialize 125 | mcdict = dict() 126 | 127 | for idf_hex, idf in concepts.items(): 128 | mcdict[idf_hex] = dict() 129 | for idf_var, cls in idf.items(): 130 | mcdict[idf_hex][idf_var] = [ 131 | {'description': process_desc(c.description), 'arity': c.arity, 'affixes': c.affixes} for c in cls 132 | ] 133 | 134 | return mcdict 135 | 136 | 137 | class MioGattoServer: 138 | def __init__(self, paper_id: str, tree, mi_anno: MiAnno, mcdict: McDict, logger: Logger): 139 | self.paper_id = paper_id 140 | self.tree = tree 141 | self.mi_anno = mi_anno 142 | self.mcdict = mcdict 143 | self.logger = logger 144 | 145 | # Start with 0 (can be considered as the number of times the mcdict is edited) 146 | self.mcdict_edit_id = 0 147 | 148 | def index(self): 149 | # avoid destroying the original tree 150 | copied_tree = deepcopy(self.tree) 151 | root = copied_tree.getroot() 152 | 153 | # add data-math-concept for each mi element 154 | for mi in root.xpath('//mi'): 155 | mi_id = mi.get('id', None) 156 | if mi_id is None: 157 | continue 158 | 159 | concept_id = self.mi_anno.occr.get(mi_id, dict()).get('concept_id', None) 160 | if concept_id is None: 161 | continue 162 | 163 | mi.attrib['data-math-concept'] = str(concept_id) 164 | 165 | # progress info 166 | nof_anno = len(self.mi_anno.occr) 167 | nof_done = sum(1 for v in self.mi_anno.occr.values() if not v['concept_id'] is None) 168 | p_concept = '{}/{} ({:.2f}%)'.format(nof_done, nof_anno, nof_done / nof_anno * 100) 169 | 170 | nof_sog = 0 171 | for anno in self.mi_anno.occr.values(): 172 | for sog in anno['sog']: 173 | nof_sog += 1 174 | 175 | # construction 176 | title = root.xpath('//head/title')[0].text 177 | body = root.xpath('body')[0] 178 | main_content = etree.tostring(body, method='html', encoding=str) 179 | 180 | return render_template( 181 | 'index.html', 182 | title=title, 183 | version=VERSION, 184 | git_revision=GIT_REVISON, 185 | paper_id=self.paper_id, 186 | annotator=self.mi_anno.annotator, 187 | p_concept=p_concept, 188 | nof_sog=nof_sog, 189 | affixes=Markup(affixes_pulldowns()), 190 | main_content=Markup(main_content), 191 | ) 192 | 193 | def assign_concept(self): 194 | res = request.form 195 | 196 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 197 | edit_id_in_request = res.get('mcdict_edit_id') 198 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 199 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 200 | return redirect('/') 201 | 202 | mi_id = res['mi_id'] 203 | concept_id = int(res['concept']) 204 | 205 | if res.get('concept'): 206 | # register 207 | self.mi_anno.occr[mi_id]['concept_id'] = concept_id 208 | self.mi_anno.dump() 209 | 210 | return redirect('/') 211 | 212 | def remove_concept(self): 213 | res = request.form 214 | 215 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 216 | edit_id_in_request = res.get('mcdict_edit_id') 217 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 218 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 219 | return redirect('/') 220 | 221 | mi_id = res['mi_id'] 222 | self.mi_anno.occr[mi_id]['concept_id'] = None 223 | self.mi_anno.dump() 224 | 225 | return redirect('/') 226 | 227 | def new_concept(self): 228 | res = request.form 229 | 230 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 231 | edit_id_in_request = res.get('mcdict_edit_id') 232 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 233 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 234 | return redirect('/') 235 | 236 | idf_hex = res.get('idf_hex') 237 | idf_var = res.get('idf_var') 238 | 239 | # make concept with checking 240 | concept = make_concept(res) 241 | if concept is None: 242 | return redirect('/') 243 | 244 | # register 245 | self.mcdict.concepts[idf_hex][idf_var].append(concept) 246 | self.mcdict.dump() 247 | 248 | self.update_mcdict_edit_id() 249 | 250 | return redirect('/') 251 | 252 | def update_concept(self): 253 | # register and save data_anno 254 | res = request.form 255 | 256 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 257 | edit_id_in_request = res.get('mcdict_edit_id') 258 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 259 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 260 | return redirect('/') 261 | 262 | idf_hex = res.get('idf_hex') 263 | idf_var = res.get('idf_var') 264 | concept_id = int(res.get('concept_id')) 265 | 266 | # make concept with checking 267 | concept = make_concept(res) 268 | if concept is None: 269 | return redirect('/') 270 | 271 | self.mcdict.concepts[idf_hex][idf_var][concept_id] = concept 272 | self.mcdict.dump() 273 | 274 | self.update_mcdict_edit_id() 275 | 276 | return redirect('/') 277 | 278 | # Naive. 279 | def update_concept_for_edit_mcdict(self): 280 | # register and save data_anno 281 | res = request.form 282 | 283 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 284 | edit_id_in_request = res.get('mcdict_edit_id') 285 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 286 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 287 | return redirect('/edit_mcdict') 288 | 289 | idf_hex = res.get('idf_hex') 290 | idf_var = res.get('idf_var') 291 | concept_id = int(res.get('concept_id')) 292 | 293 | # make concept with checking 294 | concept = make_concept(res) 295 | if concept is None: 296 | return redirect('/edit_mcdict') 297 | 298 | self.mcdict.concepts[idf_hex][idf_var][concept_id] = concept 299 | self.mcdict.dump() 300 | 301 | self.update_mcdict_edit_id() 302 | 303 | return redirect('/edit_mcdict') 304 | 305 | def add_sog(self): 306 | res = request.form 307 | 308 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 309 | edit_id_in_request = res.get('mcdict_edit_id') 310 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 311 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 312 | return redirect('/') 313 | 314 | mi_id = res['mi_id'] 315 | start_id, stop_id = res['start_id'], res['stop_id'] 316 | 317 | # TODO: validate the span range 318 | existing_sog_pos = [(s['start'], s['stop']) for s in self.mi_anno.occr[mi_id]['sog']] 319 | if (start_id, stop_id) not in existing_sog_pos: 320 | self.mi_anno.occr[mi_id]['sog'].append({'start': start_id, 'stop': stop_id, 'type': 0}) 321 | self.mi_anno.dump() 322 | 323 | return redirect('/') 324 | 325 | def delete_sog(self): 326 | res = request.form 327 | 328 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 329 | edit_id_in_request = res.get('mcdict_edit_id') 330 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 331 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 332 | return redirect('/') 333 | 334 | mi_id = res['mi_id'] 335 | start_id, stop_id = res['start_id'], res['stop_id'] 336 | 337 | delete_idx = None 338 | for idx, sog in enumerate(self.mi_anno.occr[mi_id]['sog']): 339 | if sog['start'] == start_id and sog['stop'] == stop_id: 340 | delete_idx = idx 341 | break 342 | 343 | if delete_idx is not None: 344 | del self.mi_anno.occr[mi_id]['sog'][delete_idx] 345 | self.mi_anno.dump() 346 | 347 | return redirect('/') 348 | 349 | def change_sog_type(self): 350 | res = request.form 351 | 352 | # If the mcdict used in the request differs from the latest, then redirect (i.e., reload the page). 353 | edit_id_in_request = res.get('mcdict_edit_id') 354 | if edit_id_in_request is None or str(self.mcdict_edit_id) != edit_id_in_request: 355 | flash('Invalid Action!!! Reloading the page since the mcdict has been modified.') 356 | return redirect('/') 357 | 358 | mi_id = res['mi_id'] 359 | start_id, stop_id = res['start_id'], res['stop_id'] 360 | sog_type = res['sog_type'] 361 | 362 | for sog in self.mi_anno.occr[mi_id]['sog']: 363 | if sog['start'] == start_id and sog['stop'] == stop_id: 364 | sog['type'] = sog_type 365 | self.mi_anno.dump() 366 | break 367 | 368 | return redirect('/') 369 | 370 | def gen_mcdict_json(self): 371 | data = preprocess_mcdict(self.mcdict.concepts) 372 | 373 | extended_data = [str(self.mcdict_edit_id), data] 374 | 375 | return json.dumps(extended_data, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')) 376 | 377 | def gen_sog_json(self): 378 | data = {'sog': []} 379 | 380 | for mi_id, anno in self.mi_anno.occr.items(): 381 | for sog in anno['sog']: 382 | data['sog'].append( 383 | {'mi_id': mi_id, 'start_id': sog['start'], 'stop_id': sog['stop'], 'type': sog['type']} 384 | ) 385 | 386 | return json.dumps(data, ensure_ascii=False, indent=4, sort_keys=True, separators=(',', ': ')) 387 | 388 | def edit_mcdict(self): 389 | # Copy and paste of index. 390 | # Need to add main_content to calculate statistics for identifiers and concepts. 391 | 392 | # avoid destroying the original tree 393 | copied_tree = deepcopy(self.tree) 394 | root = copied_tree.getroot() 395 | 396 | # add data-math-concept for each mi element 397 | for mi in root.xpath('//mi'): 398 | mi_id = mi.get('id', None) 399 | if mi_id is None: 400 | continue 401 | 402 | concept_id = self.mi_anno.occr.get(mi_id, dict()).get('concept_id', None) 403 | if concept_id is None: 404 | continue 405 | 406 | mi.attrib['data-math-concept'] = str(concept_id) 407 | 408 | # construction 409 | body = root.xpath('body')[0] 410 | main_content = etree.tostring(body, method='html', encoding=str) 411 | return render_template( 412 | 'edit_mcdict.html', 413 | version=VERSION, 414 | git_revision=GIT_REVISON, 415 | paper_id=self.paper_id, 416 | annotator=self.mi_anno.annotator, 417 | affixes=Markup(affixes_pulldowns()), 418 | main_content=Markup(main_content), 419 | ) 420 | 421 | def update_mcdict_edit_id(self): 422 | self.mcdict_edit_id += 1 423 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/jquery-ui.theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI CSS Framework 1.12.1 3 | * http://jqueryui.com 4 | * 5 | * Copyright jQuery Foundation and other contributors 6 | * Released under the MIT license. 7 | * http://jquery.org/license 8 | * 9 | * http://api.jqueryui.com/category/theming/ 10 | * 11 | * To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 12 | */ 13 | 14 | 15 | /* Component containers 16 | ----------------------------------*/ 17 | .ui-widget { 18 | font-family: Arial,Helvetica,sans-serif; 19 | font-size: 1em; 20 | } 21 | .ui-widget .ui-widget { 22 | font-size: 1em; 23 | } 24 | .ui-widget input, 25 | .ui-widget select, 26 | .ui-widget textarea, 27 | .ui-widget button { 28 | font-family: Arial,Helvetica,sans-serif; 29 | font-size: 1em; 30 | } 31 | .ui-widget.ui-widget-content { 32 | border: 1px solid #c5c5c5; 33 | } 34 | .ui-widget-content { 35 | border: 1px solid #dddddd; 36 | background: #ffffff; 37 | color: #333333; 38 | } 39 | .ui-widget-content a { 40 | color: #333333; 41 | } 42 | .ui-widget-header { 43 | border: 1px solid #dddddd; 44 | background: #e9e9e9; 45 | color: #333333; 46 | font-weight: bold; 47 | } 48 | .ui-widget-header a { 49 | color: #333333; 50 | } 51 | 52 | /* Interaction states 53 | ----------------------------------*/ 54 | .ui-state-default, 55 | .ui-widget-content .ui-state-default, 56 | .ui-widget-header .ui-state-default, 57 | .ui-button, 58 | 59 | /* We use html here because we need a greater specificity to make sure disabled 60 | works properly when clicked or hovered */ 61 | html .ui-button.ui-state-disabled:hover, 62 | html .ui-button.ui-state-disabled:active { 63 | border: 1px solid #c5c5c5; 64 | background: #f6f6f6; 65 | font-weight: normal; 66 | color: #454545; 67 | } 68 | .ui-state-default a, 69 | .ui-state-default a:link, 70 | .ui-state-default a:visited, 71 | a.ui-button, 72 | a:link.ui-button, 73 | a:visited.ui-button, 74 | .ui-button { 75 | color: #454545; 76 | text-decoration: none; 77 | } 78 | .ui-state-hover, 79 | .ui-widget-content .ui-state-hover, 80 | .ui-widget-header .ui-state-hover, 81 | .ui-state-focus, 82 | .ui-widget-content .ui-state-focus, 83 | .ui-widget-header .ui-state-focus, 84 | .ui-button:hover, 85 | .ui-button:focus { 86 | border: 1px solid #cccccc; 87 | background: #ededed; 88 | font-weight: normal; 89 | color: #2b2b2b; 90 | } 91 | .ui-state-hover a, 92 | .ui-state-hover a:hover, 93 | .ui-state-hover a:link, 94 | .ui-state-hover a:visited, 95 | .ui-state-focus a, 96 | .ui-state-focus a:hover, 97 | .ui-state-focus a:link, 98 | .ui-state-focus a:visited, 99 | a.ui-button:hover, 100 | a.ui-button:focus { 101 | color: #2b2b2b; 102 | text-decoration: none; 103 | } 104 | 105 | .ui-visual-focus { 106 | box-shadow: 0 0 3px 1px rgb(94, 158, 214); 107 | } 108 | .ui-state-active, 109 | .ui-widget-content .ui-state-active, 110 | .ui-widget-header .ui-state-active, 111 | a.ui-button:active, 112 | .ui-button:active, 113 | .ui-button.ui-state-active:hover { 114 | border: 1px solid #003eff; 115 | background: #007fff; 116 | font-weight: normal; 117 | color: #ffffff; 118 | } 119 | .ui-icon-background, 120 | .ui-state-active .ui-icon-background { 121 | border: #003eff; 122 | background-color: #ffffff; 123 | } 124 | .ui-state-active a, 125 | .ui-state-active a:link, 126 | .ui-state-active a:visited { 127 | color: #ffffff; 128 | text-decoration: none; 129 | } 130 | 131 | /* Interaction Cues 132 | ----------------------------------*/ 133 | .ui-state-highlight, 134 | .ui-widget-content .ui-state-highlight, 135 | .ui-widget-header .ui-state-highlight { 136 | border: 1px solid #dad55e; 137 | background: #fffa90; 138 | color: #777620; 139 | } 140 | .ui-state-checked { 141 | border: 1px solid #dad55e; 142 | background: #fffa90; 143 | } 144 | .ui-state-highlight a, 145 | .ui-widget-content .ui-state-highlight a, 146 | .ui-widget-header .ui-state-highlight a { 147 | color: #777620; 148 | } 149 | .ui-state-error, 150 | .ui-widget-content .ui-state-error, 151 | .ui-widget-header .ui-state-error { 152 | border: 1px solid #f1a899; 153 | background: #fddfdf; 154 | color: #5f3f3f; 155 | } 156 | .ui-state-error a, 157 | .ui-widget-content .ui-state-error a, 158 | .ui-widget-header .ui-state-error a { 159 | color: #5f3f3f; 160 | } 161 | .ui-state-error-text, 162 | .ui-widget-content .ui-state-error-text, 163 | .ui-widget-header .ui-state-error-text { 164 | color: #5f3f3f; 165 | } 166 | .ui-priority-primary, 167 | .ui-widget-content .ui-priority-primary, 168 | .ui-widget-header .ui-priority-primary { 169 | font-weight: bold; 170 | } 171 | .ui-priority-secondary, 172 | .ui-widget-content .ui-priority-secondary, 173 | .ui-widget-header .ui-priority-secondary { 174 | opacity: .7; 175 | filter:Alpha(Opacity=70); /* support: IE8 */ 176 | font-weight: normal; 177 | } 178 | .ui-state-disabled, 179 | .ui-widget-content .ui-state-disabled, 180 | .ui-widget-header .ui-state-disabled { 181 | opacity: .35; 182 | filter:Alpha(Opacity=35); /* support: IE8 */ 183 | background-image: none; 184 | } 185 | .ui-state-disabled .ui-icon { 186 | filter:Alpha(Opacity=35); /* support: IE8 - See #6059 */ 187 | } 188 | 189 | /* Icons 190 | ----------------------------------*/ 191 | 192 | /* states and images */ 193 | .ui-icon { 194 | width: 16px; 195 | height: 16px; 196 | } 197 | .ui-icon, 198 | .ui-widget-content .ui-icon { 199 | background-image: url("images/ui-icons_444444_256x240.png"); 200 | } 201 | .ui-widget-header .ui-icon { 202 | background-image: url("images/ui-icons_444444_256x240.png"); 203 | } 204 | .ui-state-hover .ui-icon, 205 | .ui-state-focus .ui-icon, 206 | .ui-button:hover .ui-icon, 207 | .ui-button:focus .ui-icon { 208 | background-image: url("images/ui-icons_555555_256x240.png"); 209 | } 210 | .ui-state-active .ui-icon, 211 | .ui-button:active .ui-icon { 212 | background-image: url("images/ui-icons_ffffff_256x240.png"); 213 | } 214 | .ui-state-highlight .ui-icon, 215 | .ui-button .ui-state-highlight.ui-icon { 216 | background-image: url("images/ui-icons_777620_256x240.png"); 217 | } 218 | .ui-state-error .ui-icon, 219 | .ui-state-error-text .ui-icon { 220 | background-image: url("images/ui-icons_cc0000_256x240.png"); 221 | } 222 | .ui-button .ui-icon { 223 | background-image: url("images/ui-icons_777777_256x240.png"); 224 | } 225 | 226 | /* positioning */ 227 | .ui-icon-blank { background-position: 16px 16px; } 228 | .ui-icon-caret-1-n { background-position: 0 0; } 229 | .ui-icon-caret-1-ne { background-position: -16px 0; } 230 | .ui-icon-caret-1-e { background-position: -32px 0; } 231 | .ui-icon-caret-1-se { background-position: -48px 0; } 232 | .ui-icon-caret-1-s { background-position: -65px 0; } 233 | .ui-icon-caret-1-sw { background-position: -80px 0; } 234 | .ui-icon-caret-1-w { background-position: -96px 0; } 235 | .ui-icon-caret-1-nw { background-position: -112px 0; } 236 | .ui-icon-caret-2-n-s { background-position: -128px 0; } 237 | .ui-icon-caret-2-e-w { background-position: -144px 0; } 238 | .ui-icon-triangle-1-n { background-position: 0 -16px; } 239 | .ui-icon-triangle-1-ne { background-position: -16px -16px; } 240 | .ui-icon-triangle-1-e { background-position: -32px -16px; } 241 | .ui-icon-triangle-1-se { background-position: -48px -16px; } 242 | .ui-icon-triangle-1-s { background-position: -65px -16px; } 243 | .ui-icon-triangle-1-sw { background-position: -80px -16px; } 244 | .ui-icon-triangle-1-w { background-position: -96px -16px; } 245 | .ui-icon-triangle-1-nw { background-position: -112px -16px; } 246 | .ui-icon-triangle-2-n-s { background-position: -128px -16px; } 247 | .ui-icon-triangle-2-e-w { background-position: -144px -16px; } 248 | .ui-icon-arrow-1-n { background-position: 0 -32px; } 249 | .ui-icon-arrow-1-ne { background-position: -16px -32px; } 250 | .ui-icon-arrow-1-e { background-position: -32px -32px; } 251 | .ui-icon-arrow-1-se { background-position: -48px -32px; } 252 | .ui-icon-arrow-1-s { background-position: -65px -32px; } 253 | .ui-icon-arrow-1-sw { background-position: -80px -32px; } 254 | .ui-icon-arrow-1-w { background-position: -96px -32px; } 255 | .ui-icon-arrow-1-nw { background-position: -112px -32px; } 256 | .ui-icon-arrow-2-n-s { background-position: -128px -32px; } 257 | .ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } 258 | .ui-icon-arrow-2-e-w { background-position: -160px -32px; } 259 | .ui-icon-arrow-2-se-nw { background-position: -176px -32px; } 260 | .ui-icon-arrowstop-1-n { background-position: -192px -32px; } 261 | .ui-icon-arrowstop-1-e { background-position: -208px -32px; } 262 | .ui-icon-arrowstop-1-s { background-position: -224px -32px; } 263 | .ui-icon-arrowstop-1-w { background-position: -240px -32px; } 264 | .ui-icon-arrowthick-1-n { background-position: 1px -48px; } 265 | .ui-icon-arrowthick-1-ne { background-position: -16px -48px; } 266 | .ui-icon-arrowthick-1-e { background-position: -32px -48px; } 267 | .ui-icon-arrowthick-1-se { background-position: -48px -48px; } 268 | .ui-icon-arrowthick-1-s { background-position: -64px -48px; } 269 | .ui-icon-arrowthick-1-sw { background-position: -80px -48px; } 270 | .ui-icon-arrowthick-1-w { background-position: -96px -48px; } 271 | .ui-icon-arrowthick-1-nw { background-position: -112px -48px; } 272 | .ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } 273 | .ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } 274 | .ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } 275 | .ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } 276 | .ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } 277 | .ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } 278 | .ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } 279 | .ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } 280 | .ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } 281 | .ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } 282 | .ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } 283 | .ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } 284 | .ui-icon-arrowreturn-1-w { background-position: -64px -64px; } 285 | .ui-icon-arrowreturn-1-n { background-position: -80px -64px; } 286 | .ui-icon-arrowreturn-1-e { background-position: -96px -64px; } 287 | .ui-icon-arrowreturn-1-s { background-position: -112px -64px; } 288 | .ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } 289 | .ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } 290 | .ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } 291 | .ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } 292 | .ui-icon-arrow-4 { background-position: 0 -80px; } 293 | .ui-icon-arrow-4-diag { background-position: -16px -80px; } 294 | .ui-icon-extlink { background-position: -32px -80px; } 295 | .ui-icon-newwin { background-position: -48px -80px; } 296 | .ui-icon-refresh { background-position: -64px -80px; } 297 | .ui-icon-shuffle { background-position: -80px -80px; } 298 | .ui-icon-transfer-e-w { background-position: -96px -80px; } 299 | .ui-icon-transferthick-e-w { background-position: -112px -80px; } 300 | .ui-icon-folder-collapsed { background-position: 0 -96px; } 301 | .ui-icon-folder-open { background-position: -16px -96px; } 302 | .ui-icon-document { background-position: -32px -96px; } 303 | .ui-icon-document-b { background-position: -48px -96px; } 304 | .ui-icon-note { background-position: -64px -96px; } 305 | .ui-icon-mail-closed { background-position: -80px -96px; } 306 | .ui-icon-mail-open { background-position: -96px -96px; } 307 | .ui-icon-suitcase { background-position: -112px -96px; } 308 | .ui-icon-comment { background-position: -128px -96px; } 309 | .ui-icon-person { background-position: -144px -96px; } 310 | .ui-icon-print { background-position: -160px -96px; } 311 | .ui-icon-trash { background-position: -176px -96px; } 312 | .ui-icon-locked { background-position: -192px -96px; } 313 | .ui-icon-unlocked { background-position: -208px -96px; } 314 | .ui-icon-bookmark { background-position: -224px -96px; } 315 | .ui-icon-tag { background-position: -240px -96px; } 316 | .ui-icon-home { background-position: 0 -112px; } 317 | .ui-icon-flag { background-position: -16px -112px; } 318 | .ui-icon-calendar { background-position: -32px -112px; } 319 | .ui-icon-cart { background-position: -48px -112px; } 320 | .ui-icon-pencil { background-position: -64px -112px; } 321 | .ui-icon-clock { background-position: -80px -112px; } 322 | .ui-icon-disk { background-position: -96px -112px; } 323 | .ui-icon-calculator { background-position: -112px -112px; } 324 | .ui-icon-zoomin { background-position: -128px -112px; } 325 | .ui-icon-zoomout { background-position: -144px -112px; } 326 | .ui-icon-search { background-position: -160px -112px; } 327 | .ui-icon-wrench { background-position: -176px -112px; } 328 | .ui-icon-gear { background-position: -192px -112px; } 329 | .ui-icon-heart { background-position: -208px -112px; } 330 | .ui-icon-star { background-position: -224px -112px; } 331 | .ui-icon-link { background-position: -240px -112px; } 332 | .ui-icon-cancel { background-position: 0 -128px; } 333 | .ui-icon-plus { background-position: -16px -128px; } 334 | .ui-icon-plusthick { background-position: -32px -128px; } 335 | .ui-icon-minus { background-position: -48px -128px; } 336 | .ui-icon-minusthick { background-position: -64px -128px; } 337 | .ui-icon-close { background-position: -80px -128px; } 338 | .ui-icon-closethick { background-position: -96px -128px; } 339 | .ui-icon-key { background-position: -112px -128px; } 340 | .ui-icon-lightbulb { background-position: -128px -128px; } 341 | .ui-icon-scissors { background-position: -144px -128px; } 342 | .ui-icon-clipboard { background-position: -160px -128px; } 343 | .ui-icon-copy { background-position: -176px -128px; } 344 | .ui-icon-contact { background-position: -192px -128px; } 345 | .ui-icon-image { background-position: -208px -128px; } 346 | .ui-icon-video { background-position: -224px -128px; } 347 | .ui-icon-script { background-position: -240px -128px; } 348 | .ui-icon-alert { background-position: 0 -144px; } 349 | .ui-icon-info { background-position: -16px -144px; } 350 | .ui-icon-notice { background-position: -32px -144px; } 351 | .ui-icon-help { background-position: -48px -144px; } 352 | .ui-icon-check { background-position: -64px -144px; } 353 | .ui-icon-bullet { background-position: -80px -144px; } 354 | .ui-icon-radio-on { background-position: -96px -144px; } 355 | .ui-icon-radio-off { background-position: -112px -144px; } 356 | .ui-icon-pin-w { background-position: -128px -144px; } 357 | .ui-icon-pin-s { background-position: -144px -144px; } 358 | .ui-icon-play { background-position: 0 -160px; } 359 | .ui-icon-pause { background-position: -16px -160px; } 360 | .ui-icon-seek-next { background-position: -32px -160px; } 361 | .ui-icon-seek-prev { background-position: -48px -160px; } 362 | .ui-icon-seek-end { background-position: -64px -160px; } 363 | .ui-icon-seek-start { background-position: -80px -160px; } 364 | /* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ 365 | .ui-icon-seek-first { background-position: -80px -160px; } 366 | .ui-icon-stop { background-position: -96px -160px; } 367 | .ui-icon-eject { background-position: -112px -160px; } 368 | .ui-icon-volume-off { background-position: -128px -160px; } 369 | .ui-icon-volume-on { background-position: -144px -160px; } 370 | .ui-icon-power { background-position: 0 -176px; } 371 | .ui-icon-signal-diag { background-position: -16px -176px; } 372 | .ui-icon-signal { background-position: -32px -176px; } 373 | .ui-icon-battery-0 { background-position: -48px -176px; } 374 | .ui-icon-battery-1 { background-position: -64px -176px; } 375 | .ui-icon-battery-2 { background-position: -80px -176px; } 376 | .ui-icon-battery-3 { background-position: -96px -176px; } 377 | .ui-icon-circle-plus { background-position: 0 -192px; } 378 | .ui-icon-circle-minus { background-position: -16px -192px; } 379 | .ui-icon-circle-close { background-position: -32px -192px; } 380 | .ui-icon-circle-triangle-e { background-position: -48px -192px; } 381 | .ui-icon-circle-triangle-s { background-position: -64px -192px; } 382 | .ui-icon-circle-triangle-w { background-position: -80px -192px; } 383 | .ui-icon-circle-triangle-n { background-position: -96px -192px; } 384 | .ui-icon-circle-arrow-e { background-position: -112px -192px; } 385 | .ui-icon-circle-arrow-s { background-position: -128px -192px; } 386 | .ui-icon-circle-arrow-w { background-position: -144px -192px; } 387 | .ui-icon-circle-arrow-n { background-position: -160px -192px; } 388 | .ui-icon-circle-zoomin { background-position: -176px -192px; } 389 | .ui-icon-circle-zoomout { background-position: -192px -192px; } 390 | .ui-icon-circle-check { background-position: -208px -192px; } 391 | .ui-icon-circlesmall-plus { background-position: 0 -208px; } 392 | .ui-icon-circlesmall-minus { background-position: -16px -208px; } 393 | .ui-icon-circlesmall-close { background-position: -32px -208px; } 394 | .ui-icon-squaresmall-plus { background-position: -48px -208px; } 395 | .ui-icon-squaresmall-minus { background-position: -64px -208px; } 396 | .ui-icon-squaresmall-close { background-position: -80px -208px; } 397 | .ui-icon-grip-dotted-vertical { background-position: 0 -224px; } 398 | .ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } 399 | .ui-icon-grip-solid-vertical { background-position: -32px -224px; } 400 | .ui-icon-grip-solid-horizontal { background-position: -48px -224px; } 401 | .ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } 402 | .ui-icon-grip-diagonal-se { background-position: -80px -224px; } 403 | 404 | 405 | /* Misc visuals 406 | ----------------------------------*/ 407 | 408 | /* Corner radius */ 409 | .ui-corner-all, 410 | .ui-corner-top, 411 | .ui-corner-left, 412 | .ui-corner-tl { 413 | border-top-left-radius: 3px; 414 | } 415 | .ui-corner-all, 416 | .ui-corner-top, 417 | .ui-corner-right, 418 | .ui-corner-tr { 419 | border-top-right-radius: 3px; 420 | } 421 | .ui-corner-all, 422 | .ui-corner-bottom, 423 | .ui-corner-left, 424 | .ui-corner-bl { 425 | border-bottom-left-radius: 3px; 426 | } 427 | .ui-corner-all, 428 | .ui-corner-bottom, 429 | .ui-corner-right, 430 | .ui-corner-br { 431 | border-bottom-right-radius: 3px; 432 | } 433 | 434 | /* Overlays */ 435 | .ui-widget-overlay { 436 | background: #aaaaaa; 437 | opacity: .003; 438 | filter: Alpha(Opacity=.3); /* support: IE8 */ 439 | } 440 | .ui-widget-shadow { 441 | -webkit-box-shadow: 0px 0px 5px #666666; 442 | box-shadow: 0px 0px 5px #666666; 443 | } 444 | -------------------------------------------------------------------------------- /static/vendor/jquery-ui-1.12.1/jquery-ui.structure.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery UI CSS Framework 1.12.1 3 | * http://jqueryui.com 4 | * 5 | * Copyright jQuery Foundation and other contributors 6 | * Released under the MIT license. 7 | * http://jquery.org/license 8 | * 9 | * http://api.jqueryui.com/category/theming/ 10 | */ 11 | /* Layout helpers 12 | ----------------------------------*/ 13 | .ui-helper-hidden { 14 | display: none; 15 | } 16 | .ui-helper-hidden-accessible { 17 | border: 0; 18 | clip: rect(0 0 0 0); 19 | height: 1px; 20 | margin: -1px; 21 | overflow: hidden; 22 | padding: 0; 23 | position: absolute; 24 | width: 1px; 25 | } 26 | .ui-helper-reset { 27 | margin: 0; 28 | padding: 0; 29 | border: 0; 30 | outline: 0; 31 | line-height: 1.3; 32 | text-decoration: none; 33 | font-size: 100%; 34 | list-style: none; 35 | } 36 | .ui-helper-clearfix:before, 37 | .ui-helper-clearfix:after { 38 | content: ""; 39 | display: table; 40 | border-collapse: collapse; 41 | } 42 | .ui-helper-clearfix:after { 43 | clear: both; 44 | } 45 | .ui-helper-zfix { 46 | width: 100%; 47 | height: 100%; 48 | top: 0; 49 | left: 0; 50 | position: absolute; 51 | opacity: 0; 52 | filter:Alpha(Opacity=0); /* support: IE8 */ 53 | } 54 | 55 | .ui-front { 56 | z-index: 100; 57 | } 58 | 59 | 60 | /* Interaction Cues 61 | ----------------------------------*/ 62 | .ui-state-disabled { 63 | cursor: default !important; 64 | pointer-events: none; 65 | } 66 | 67 | 68 | /* Icons 69 | ----------------------------------*/ 70 | .ui-icon { 71 | display: inline-block; 72 | vertical-align: middle; 73 | margin-top: -.25em; 74 | position: relative; 75 | text-indent: -99999px; 76 | overflow: hidden; 77 | background-repeat: no-repeat; 78 | } 79 | 80 | .ui-widget-icon-block { 81 | left: 50%; 82 | margin-left: -8px; 83 | display: block; 84 | } 85 | 86 | /* Misc visuals 87 | ----------------------------------*/ 88 | 89 | /* Overlays */ 90 | .ui-widget-overlay { 91 | position: fixed; 92 | top: 0; 93 | left: 0; 94 | width: 100%; 95 | height: 100%; 96 | } 97 | .ui-accordion .ui-accordion-header { 98 | display: block; 99 | cursor: pointer; 100 | position: relative; 101 | margin: 2px 0 0 0; 102 | padding: .5em .5em .5em .7em; 103 | font-size: 100%; 104 | } 105 | .ui-accordion .ui-accordion-content { 106 | padding: 1em 2.2em; 107 | border-top: 0; 108 | overflow: auto; 109 | } 110 | .ui-autocomplete { 111 | position: absolute; 112 | top: 0; 113 | left: 0; 114 | cursor: default; 115 | } 116 | .ui-menu { 117 | list-style: none; 118 | padding: 0; 119 | margin: 0; 120 | display: block; 121 | outline: 0; 122 | } 123 | .ui-menu .ui-menu { 124 | position: absolute; 125 | } 126 | .ui-menu .ui-menu-item { 127 | margin: 0; 128 | cursor: pointer; 129 | /* support: IE10, see #8844 */ 130 | list-style-image: url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7"); 131 | } 132 | .ui-menu .ui-menu-item-wrapper { 133 | position: relative; 134 | padding: 3px 1em 3px .4em; 135 | } 136 | .ui-menu .ui-menu-divider { 137 | margin: 5px 0; 138 | height: 0; 139 | font-size: 0; 140 | line-height: 0; 141 | border-width: 1px 0 0 0; 142 | } 143 | .ui-menu .ui-state-focus, 144 | .ui-menu .ui-state-active { 145 | margin: -1px; 146 | } 147 | 148 | /* icon support */ 149 | .ui-menu-icons { 150 | position: relative; 151 | } 152 | .ui-menu-icons .ui-menu-item-wrapper { 153 | padding-left: 2em; 154 | } 155 | 156 | /* left-aligned */ 157 | .ui-menu .ui-icon { 158 | position: absolute; 159 | top: 0; 160 | bottom: 0; 161 | left: .2em; 162 | margin: auto 0; 163 | } 164 | 165 | /* right-aligned */ 166 | .ui-menu .ui-menu-icon { 167 | left: auto; 168 | right: 0; 169 | } 170 | .ui-button { 171 | padding: .4em 1em; 172 | display: inline-block; 173 | position: relative; 174 | line-height: normal; 175 | margin-right: .1em; 176 | cursor: pointer; 177 | vertical-align: middle; 178 | text-align: center; 179 | -webkit-user-select: none; 180 | -moz-user-select: none; 181 | -ms-user-select: none; 182 | user-select: none; 183 | 184 | /* Support: IE <= 11 */ 185 | overflow: visible; 186 | } 187 | 188 | .ui-button, 189 | .ui-button:link, 190 | .ui-button:visited, 191 | .ui-button:hover, 192 | .ui-button:active { 193 | text-decoration: none; 194 | } 195 | 196 | /* to make room for the icon, a width needs to be set here */ 197 | .ui-button-icon-only { 198 | width: 2em; 199 | box-sizing: border-box; 200 | text-indent: -9999px; 201 | white-space: nowrap; 202 | } 203 | 204 | /* no icon support for input elements */ 205 | input.ui-button.ui-button-icon-only { 206 | text-indent: 0; 207 | } 208 | 209 | /* button icon element(s) */ 210 | .ui-button-icon-only .ui-icon { 211 | position: absolute; 212 | top: 50%; 213 | left: 50%; 214 | margin-top: -8px; 215 | margin-left: -8px; 216 | } 217 | 218 | .ui-button.ui-icon-notext .ui-icon { 219 | padding: 0; 220 | width: 2.1em; 221 | height: 2.1em; 222 | text-indent: -9999px; 223 | white-space: nowrap; 224 | 225 | } 226 | 227 | input.ui-button.ui-icon-notext .ui-icon { 228 | width: auto; 229 | height: auto; 230 | text-indent: 0; 231 | white-space: normal; 232 | padding: .4em 1em; 233 | } 234 | 235 | /* workarounds */ 236 | /* Support: Firefox 5 - 40 */ 237 | input.ui-button::-moz-focus-inner, 238 | button.ui-button::-moz-focus-inner { 239 | border: 0; 240 | padding: 0; 241 | } 242 | .ui-controlgroup { 243 | vertical-align: middle; 244 | display: inline-block; 245 | } 246 | .ui-controlgroup > .ui-controlgroup-item { 247 | float: left; 248 | margin-left: 0; 249 | margin-right: 0; 250 | } 251 | .ui-controlgroup > .ui-controlgroup-item:focus, 252 | .ui-controlgroup > .ui-controlgroup-item.ui-visual-focus { 253 | z-index: 9999; 254 | } 255 | .ui-controlgroup-vertical > .ui-controlgroup-item { 256 | display: block; 257 | float: none; 258 | width: 100%; 259 | margin-top: 0; 260 | margin-bottom: 0; 261 | text-align: left; 262 | } 263 | .ui-controlgroup-vertical .ui-controlgroup-item { 264 | box-sizing: border-box; 265 | } 266 | .ui-controlgroup .ui-controlgroup-label { 267 | padding: .4em 1em; 268 | } 269 | .ui-controlgroup .ui-controlgroup-label span { 270 | font-size: 80%; 271 | } 272 | .ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item { 273 | border-left: none; 274 | } 275 | .ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item { 276 | border-top: none; 277 | } 278 | .ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content { 279 | border-right: none; 280 | } 281 | .ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content { 282 | border-bottom: none; 283 | } 284 | 285 | /* Spinner specific style fixes */ 286 | .ui-controlgroup-vertical .ui-spinner-input { 287 | 288 | /* Support: IE8 only, Android < 4.4 only */ 289 | width: 75%; 290 | width: calc( 100% - 2.4em ); 291 | } 292 | .ui-controlgroup-vertical .ui-spinner .ui-spinner-up { 293 | border-top-style: solid; 294 | } 295 | 296 | .ui-checkboxradio-label .ui-icon-background { 297 | box-shadow: inset 1px 1px 1px #ccc; 298 | border-radius: .12em; 299 | border: none; 300 | } 301 | .ui-checkboxradio-radio-label .ui-icon-background { 302 | width: 16px; 303 | height: 16px; 304 | border-radius: 1em; 305 | overflow: visible; 306 | border: none; 307 | } 308 | .ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon, 309 | .ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon { 310 | background-image: none; 311 | width: 8px; 312 | height: 8px; 313 | border-width: 4px; 314 | border-style: solid; 315 | } 316 | .ui-checkboxradio-disabled { 317 | pointer-events: none; 318 | } 319 | .ui-datepicker { 320 | width: 17em; 321 | padding: .2em .2em 0; 322 | display: none; 323 | } 324 | .ui-datepicker .ui-datepicker-header { 325 | position: relative; 326 | padding: .2em 0; 327 | } 328 | .ui-datepicker .ui-datepicker-prev, 329 | .ui-datepicker .ui-datepicker-next { 330 | position: absolute; 331 | top: 2px; 332 | width: 1.8em; 333 | height: 1.8em; 334 | } 335 | .ui-datepicker .ui-datepicker-prev-hover, 336 | .ui-datepicker .ui-datepicker-next-hover { 337 | top: 1px; 338 | } 339 | .ui-datepicker .ui-datepicker-prev { 340 | left: 2px; 341 | } 342 | .ui-datepicker .ui-datepicker-next { 343 | right: 2px; 344 | } 345 | .ui-datepicker .ui-datepicker-prev-hover { 346 | left: 1px; 347 | } 348 | .ui-datepicker .ui-datepicker-next-hover { 349 | right: 1px; 350 | } 351 | .ui-datepicker .ui-datepicker-prev span, 352 | .ui-datepicker .ui-datepicker-next span { 353 | display: block; 354 | position: absolute; 355 | left: 50%; 356 | margin-left: -8px; 357 | top: 50%; 358 | margin-top: -8px; 359 | } 360 | .ui-datepicker .ui-datepicker-title { 361 | margin: 0 2.3em; 362 | line-height: 1.8em; 363 | text-align: center; 364 | } 365 | .ui-datepicker .ui-datepicker-title select { 366 | font-size: 1em; 367 | margin: 1px 0; 368 | } 369 | .ui-datepicker select.ui-datepicker-month, 370 | .ui-datepicker select.ui-datepicker-year { 371 | width: 45%; 372 | } 373 | .ui-datepicker table { 374 | width: 100%; 375 | font-size: .9em; 376 | border-collapse: collapse; 377 | margin: 0 0 .4em; 378 | } 379 | .ui-datepicker th { 380 | padding: .7em .3em; 381 | text-align: center; 382 | font-weight: bold; 383 | border: 0; 384 | } 385 | .ui-datepicker td { 386 | border: 0; 387 | padding: 1px; 388 | } 389 | .ui-datepicker td span, 390 | .ui-datepicker td a { 391 | display: block; 392 | padding: .2em; 393 | text-align: right; 394 | text-decoration: none; 395 | } 396 | .ui-datepicker .ui-datepicker-buttonpane { 397 | background-image: none; 398 | margin: .7em 0 0 0; 399 | padding: 0 .2em; 400 | border-left: 0; 401 | border-right: 0; 402 | border-bottom: 0; 403 | } 404 | .ui-datepicker .ui-datepicker-buttonpane button { 405 | float: right; 406 | margin: .5em .2em .4em; 407 | cursor: pointer; 408 | padding: .2em .6em .3em .6em; 409 | width: auto; 410 | overflow: visible; 411 | } 412 | .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { 413 | float: left; 414 | } 415 | 416 | /* with multiple calendars */ 417 | .ui-datepicker.ui-datepicker-multi { 418 | width: auto; 419 | } 420 | .ui-datepicker-multi .ui-datepicker-group { 421 | float: left; 422 | } 423 | .ui-datepicker-multi .ui-datepicker-group table { 424 | width: 95%; 425 | margin: 0 auto .4em; 426 | } 427 | .ui-datepicker-multi-2 .ui-datepicker-group { 428 | width: 50%; 429 | } 430 | .ui-datepicker-multi-3 .ui-datepicker-group { 431 | width: 33.3%; 432 | } 433 | .ui-datepicker-multi-4 .ui-datepicker-group { 434 | width: 25%; 435 | } 436 | .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header, 437 | .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { 438 | border-left-width: 0; 439 | } 440 | .ui-datepicker-multi .ui-datepicker-buttonpane { 441 | clear: left; 442 | } 443 | .ui-datepicker-row-break { 444 | clear: both; 445 | width: 100%; 446 | font-size: 0; 447 | } 448 | 449 | /* RTL support */ 450 | .ui-datepicker-rtl { 451 | direction: rtl; 452 | } 453 | .ui-datepicker-rtl .ui-datepicker-prev { 454 | right: 2px; 455 | left: auto; 456 | } 457 | .ui-datepicker-rtl .ui-datepicker-next { 458 | left: 2px; 459 | right: auto; 460 | } 461 | .ui-datepicker-rtl .ui-datepicker-prev:hover { 462 | right: 1px; 463 | left: auto; 464 | } 465 | .ui-datepicker-rtl .ui-datepicker-next:hover { 466 | left: 1px; 467 | right: auto; 468 | } 469 | .ui-datepicker-rtl .ui-datepicker-buttonpane { 470 | clear: right; 471 | } 472 | .ui-datepicker-rtl .ui-datepicker-buttonpane button { 473 | float: left; 474 | } 475 | .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current, 476 | .ui-datepicker-rtl .ui-datepicker-group { 477 | float: right; 478 | } 479 | .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header, 480 | .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { 481 | border-right-width: 0; 482 | border-left-width: 1px; 483 | } 484 | 485 | /* Icons */ 486 | .ui-datepicker .ui-icon { 487 | display: block; 488 | text-indent: -99999px; 489 | overflow: hidden; 490 | background-repeat: no-repeat; 491 | left: .5em; 492 | top: .3em; 493 | } 494 | .ui-dialog { 495 | position: absolute; 496 | top: 0; 497 | left: 0; 498 | padding: .2em; 499 | outline: 0; 500 | } 501 | .ui-dialog .ui-dialog-titlebar { 502 | padding: .4em 1em; 503 | position: relative; 504 | } 505 | .ui-dialog .ui-dialog-title { 506 | float: left; 507 | margin: .1em 0; 508 | white-space: nowrap; 509 | width: 90%; 510 | overflow: hidden; 511 | text-overflow: ellipsis; 512 | } 513 | .ui-dialog .ui-dialog-titlebar-close { 514 | position: absolute; 515 | right: .3em; 516 | top: 50%; 517 | width: 20px; 518 | margin: -10px 0 0 0; 519 | padding: 1px; 520 | height: 20px; 521 | } 522 | .ui-dialog .ui-dialog-content { 523 | position: relative; 524 | border: 0; 525 | padding: .5em 1em; 526 | background: none; 527 | overflow: auto; 528 | } 529 | .ui-dialog .ui-dialog-buttonpane { 530 | text-align: left; 531 | border-width: 1px 0 0 0; 532 | background-image: none; 533 | margin-top: .5em; 534 | padding: .3em 1em .5em .4em; 535 | } 536 | .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { 537 | float: right; 538 | } 539 | .ui-dialog .ui-dialog-buttonpane button { 540 | margin: .5em .4em .5em 0; 541 | cursor: pointer; 542 | } 543 | .ui-dialog .ui-resizable-n { 544 | height: 2px; 545 | top: 0; 546 | } 547 | .ui-dialog .ui-resizable-e { 548 | width: 2px; 549 | right: 0; 550 | } 551 | .ui-dialog .ui-resizable-s { 552 | height: 2px; 553 | bottom: 0; 554 | } 555 | .ui-dialog .ui-resizable-w { 556 | width: 2px; 557 | left: 0; 558 | } 559 | .ui-dialog .ui-resizable-se, 560 | .ui-dialog .ui-resizable-sw, 561 | .ui-dialog .ui-resizable-ne, 562 | .ui-dialog .ui-resizable-nw { 563 | width: 7px; 564 | height: 7px; 565 | } 566 | .ui-dialog .ui-resizable-se { 567 | right: 0; 568 | bottom: 0; 569 | } 570 | .ui-dialog .ui-resizable-sw { 571 | left: 0; 572 | bottom: 0; 573 | } 574 | .ui-dialog .ui-resizable-ne { 575 | right: 0; 576 | top: 0; 577 | } 578 | .ui-dialog .ui-resizable-nw { 579 | left: 0; 580 | top: 0; 581 | } 582 | .ui-draggable .ui-dialog-titlebar { 583 | cursor: move; 584 | } 585 | .ui-draggable-handle { 586 | -ms-touch-action: none; 587 | touch-action: none; 588 | } 589 | .ui-resizable { 590 | position: relative; 591 | } 592 | .ui-resizable-handle { 593 | position: absolute; 594 | font-size: 0.1px; 595 | display: block; 596 | -ms-touch-action: none; 597 | touch-action: none; 598 | } 599 | .ui-resizable-disabled .ui-resizable-handle, 600 | .ui-resizable-autohide .ui-resizable-handle { 601 | display: none; 602 | } 603 | .ui-resizable-n { 604 | cursor: n-resize; 605 | height: 7px; 606 | width: 100%; 607 | top: -5px; 608 | left: 0; 609 | } 610 | .ui-resizable-s { 611 | cursor: s-resize; 612 | height: 7px; 613 | width: 100%; 614 | bottom: -5px; 615 | left: 0; 616 | } 617 | .ui-resizable-e { 618 | cursor: e-resize; 619 | width: 7px; 620 | right: -5px; 621 | top: 0; 622 | height: 100%; 623 | } 624 | .ui-resizable-w { 625 | cursor: w-resize; 626 | width: 7px; 627 | left: -5px; 628 | top: 0; 629 | height: 100%; 630 | } 631 | .ui-resizable-se { 632 | cursor: se-resize; 633 | width: 12px; 634 | height: 12px; 635 | right: 1px; 636 | bottom: 1px; 637 | } 638 | .ui-resizable-sw { 639 | cursor: sw-resize; 640 | width: 9px; 641 | height: 9px; 642 | left: -5px; 643 | bottom: -5px; 644 | } 645 | .ui-resizable-nw { 646 | cursor: nw-resize; 647 | width: 9px; 648 | height: 9px; 649 | left: -5px; 650 | top: -5px; 651 | } 652 | .ui-resizable-ne { 653 | cursor: ne-resize; 654 | width: 9px; 655 | height: 9px; 656 | right: -5px; 657 | top: -5px; 658 | } 659 | .ui-progressbar { 660 | height: 2em; 661 | text-align: left; 662 | overflow: hidden; 663 | } 664 | .ui-progressbar .ui-progressbar-value { 665 | margin: -1px; 666 | height: 100%; 667 | } 668 | .ui-progressbar .ui-progressbar-overlay { 669 | background: url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw=="); 670 | height: 100%; 671 | filter: alpha(opacity=25); /* support: IE8 */ 672 | opacity: 0.25; 673 | } 674 | .ui-progressbar-indeterminate .ui-progressbar-value { 675 | background-image: none; 676 | } 677 | .ui-selectable { 678 | -ms-touch-action: none; 679 | touch-action: none; 680 | } 681 | .ui-selectable-helper { 682 | position: absolute; 683 | z-index: 100; 684 | border: 1px dotted black; 685 | } 686 | .ui-selectmenu-menu { 687 | padding: 0; 688 | margin: 0; 689 | position: absolute; 690 | top: 0; 691 | left: 0; 692 | display: none; 693 | } 694 | .ui-selectmenu-menu .ui-menu { 695 | overflow: auto; 696 | overflow-x: hidden; 697 | padding-bottom: 1px; 698 | } 699 | .ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup { 700 | font-size: 1em; 701 | font-weight: bold; 702 | line-height: 1.5; 703 | padding: 2px 0.4em; 704 | margin: 0.5em 0 0 0; 705 | height: auto; 706 | border: 0; 707 | } 708 | .ui-selectmenu-open { 709 | display: block; 710 | } 711 | .ui-selectmenu-text { 712 | display: block; 713 | margin-right: 20px; 714 | overflow: hidden; 715 | text-overflow: ellipsis; 716 | } 717 | .ui-selectmenu-button.ui-button { 718 | text-align: left; 719 | white-space: nowrap; 720 | width: 14em; 721 | } 722 | .ui-selectmenu-icon.ui-icon { 723 | float: right; 724 | margin-top: 0; 725 | } 726 | .ui-slider { 727 | position: relative; 728 | text-align: left; 729 | } 730 | .ui-slider .ui-slider-handle { 731 | position: absolute; 732 | z-index: 2; 733 | width: 1.2em; 734 | height: 1.2em; 735 | cursor: default; 736 | -ms-touch-action: none; 737 | touch-action: none; 738 | } 739 | .ui-slider .ui-slider-range { 740 | position: absolute; 741 | z-index: 1; 742 | font-size: .7em; 743 | display: block; 744 | border: 0; 745 | background-position: 0 0; 746 | } 747 | 748 | /* support: IE8 - See #6727 */ 749 | .ui-slider.ui-state-disabled .ui-slider-handle, 750 | .ui-slider.ui-state-disabled .ui-slider-range { 751 | filter: inherit; 752 | } 753 | 754 | .ui-slider-horizontal { 755 | height: .8em; 756 | } 757 | .ui-slider-horizontal .ui-slider-handle { 758 | top: -.3em; 759 | margin-left: -.6em; 760 | } 761 | .ui-slider-horizontal .ui-slider-range { 762 | top: 0; 763 | height: 100%; 764 | } 765 | .ui-slider-horizontal .ui-slider-range-min { 766 | left: 0; 767 | } 768 | .ui-slider-horizontal .ui-slider-range-max { 769 | right: 0; 770 | } 771 | 772 | .ui-slider-vertical { 773 | width: .8em; 774 | height: 100px; 775 | } 776 | .ui-slider-vertical .ui-slider-handle { 777 | left: -.3em; 778 | margin-left: 0; 779 | margin-bottom: -.6em; 780 | } 781 | .ui-slider-vertical .ui-slider-range { 782 | left: 0; 783 | width: 100%; 784 | } 785 | .ui-slider-vertical .ui-slider-range-min { 786 | bottom: 0; 787 | } 788 | .ui-slider-vertical .ui-slider-range-max { 789 | top: 0; 790 | } 791 | .ui-sortable-handle { 792 | -ms-touch-action: none; 793 | touch-action: none; 794 | } 795 | .ui-spinner { 796 | position: relative; 797 | display: inline-block; 798 | overflow: hidden; 799 | padding: 0; 800 | vertical-align: middle; 801 | } 802 | .ui-spinner-input { 803 | border: none; 804 | background: none; 805 | color: inherit; 806 | padding: .222em 0; 807 | margin: .2em 0; 808 | vertical-align: middle; 809 | margin-left: .4em; 810 | margin-right: 2em; 811 | } 812 | .ui-spinner-button { 813 | width: 1.6em; 814 | height: 50%; 815 | font-size: .5em; 816 | padding: 0; 817 | margin: 0; 818 | text-align: center; 819 | position: absolute; 820 | cursor: default; 821 | display: block; 822 | overflow: hidden; 823 | right: 0; 824 | } 825 | /* more specificity required here to override default borders */ 826 | .ui-spinner a.ui-spinner-button { 827 | border-top-style: none; 828 | border-bottom-style: none; 829 | border-right-style: none; 830 | } 831 | .ui-spinner-up { 832 | top: 0; 833 | } 834 | .ui-spinner-down { 835 | bottom: 0; 836 | } 837 | .ui-tabs { 838 | position: relative;/* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */ 839 | padding: .2em; 840 | } 841 | .ui-tabs .ui-tabs-nav { 842 | margin: 0; 843 | padding: .2em .2em 0; 844 | } 845 | .ui-tabs .ui-tabs-nav li { 846 | list-style: none; 847 | float: left; 848 | position: relative; 849 | top: 0; 850 | margin: 1px .2em 0 0; 851 | border-bottom-width: 0; 852 | padding: 0; 853 | white-space: nowrap; 854 | } 855 | .ui-tabs .ui-tabs-nav .ui-tabs-anchor { 856 | float: left; 857 | padding: .5em 1em; 858 | text-decoration: none; 859 | } 860 | .ui-tabs .ui-tabs-nav li.ui-tabs-active { 861 | margin-bottom: -1px; 862 | padding-bottom: 1px; 863 | } 864 | .ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor, 865 | .ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor, 866 | .ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor { 867 | cursor: text; 868 | } 869 | .ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor { 870 | cursor: pointer; 871 | } 872 | .ui-tabs .ui-tabs-panel { 873 | display: block; 874 | border-width: 0; 875 | padding: 1em 1.4em; 876 | background: none; 877 | } 878 | .ui-tooltip { 879 | padding: 8px; 880 | position: absolute; 881 | z-index: 9999; 882 | max-width: 300px; 883 | } 884 | body .ui-tooltip { 885 | border-width: 2px; 886 | } 887 | --------------------------------------------------------------------------------