NILC-ICMC-USP commited on
Commit
ec63fa6
·
verified ·
1 Parent(s): 787c607

Upload 82 files

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +6 -0
  2. README.md +16 -8
  3. app.py +284 -0
  4. not_used_Dockerfile +21 -0
  5. requirements.txt +8 -0
  6. runtime.txt +1 -0
  7. src/annotation/setP11.sh +37 -0
  8. src/arborator-draft/ArboratorDraft.js +1 -0
  9. src/arborator-draft/FileSaver.min.js +3 -0
  10. src/arborator-draft/arborator-draft.css +250 -0
  11. src/arborator-draft/arborator-draft.js +691 -0
  12. src/arborator-draft/arborator-draft2.css +118 -0
  13. src/arborator-draft/arborator-draft2.js +720 -0
  14. src/arborator-draft/arborator.svg +27 -0
  15. src/arborator-draft/bootstrap.min.css +0 -0
  16. src/arborator-draft/canvg.js +0 -0
  17. src/arborator-draft/d3.js +0 -0
  18. src/arborator-draft/example_arborator-draft.html +198 -0
  19. src/arborator-draft/jquery-3.2.1.min.js +4 -0
  20. src/arborator-draft/jszip.min.js +13 -0
  21. src/arborator-draft/speedtest.oneBigConllTag.html +0 -0
  22. src/arborator-draft/speedtest.separateConllTags.html +0 -0
  23. src/evalatin2024-latinpipe/LICENSE +373 -0
  24. src/evalatin2024-latinpipe/README.md +118 -0
  25. src/evalatin2024-latinpipe/__pycache__/latinpipe_evalatin24_eval.cpython-311.pyc +0 -0
  26. src/evalatin2024-latinpipe/data/conllu_split.py +39 -0
  27. src/evalatin2024-latinpipe/data/fetch_data.sh +66 -0
  28. src/evalatin2024-latinpipe/figures/LatinPipe.svg +0 -0
  29. src/evalatin2024-latinpipe/latinpipe-evalatin24-240520/LICENSE +435 -0
  30. src/evalatin2024-latinpipe/latinpipe-evalatin24-240520/README.md +71 -0
  31. src/evalatin2024-latinpipe/latinpipe_evalatin24.py +944 -0
  32. src/evalatin2024-latinpipe/latinpipe_evalatin24_eval.py +596 -0
  33. src/evalatin2024-latinpipe/latinpipe_evalatin24_server.py +433 -0
  34. src/evalatin2024-latinpipe/parsed.conllu +20 -0
  35. src/evalatin2024-latinpipe/requirements.txt +8 -0
  36. src/img/c4ia.png +0 -0
  37. src/img/icmc.png +3 -0
  38. src/img/inova_nobackground.png +0 -0
  39. src/img/mcti_nobackground.png +0 -0
  40. src/img/motorola_nobackground.png +0 -0
  41. src/img/nilc-removebg.png +0 -0
  42. src/img/softex_nobackground.png +0 -0
  43. src/img/wordcloud_brasil5.png +3 -0
  44. src/portSentencer/abbrev.txt +397 -0
  45. src/portSentencer/portSent.py +242 -0
  46. src/portTokenizer/ADJ.tsv +0 -0
  47. src/portTokenizer/ADP.tsv +38 -0
  48. src/portTokenizer/ADV.tsv +0 -0
  49. src/portTokenizer/AUX.tsv +435 -0
  50. src/portTokenizer/CCONJ.tsv +25 -0
.gitattributes CHANGED
@@ -33,3 +33,9 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
 
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ src/img/icmc.png filter=lfs diff=lfs merge=lfs -text
37
+ src/img/wordcloud_brasil5.png filter=lfs diff=lfs merge=lfs -text
38
+ src/portTokenizer/VERB.tsv filter=lfs diff=lfs merge=lfs -text
39
+ src/portTokenizer/WORDmaster.txt filter=lfs diff=lfs merge=lfs -text
40
+ src/postproc/VERB.tsv filter=lfs diff=lfs merge=lfs -text
41
+ src/postproc/WORDmaster.txt filter=lfs diff=lfs merge=lfs -text
README.md CHANGED
@@ -1,15 +1,23 @@
1
  ---
2
  title: Portparser.v2
3
- emoji: 📈
4
- colorFrom: blue
5
- colorTo: indigo
6
  sdk: streamlit
7
- sdk_version: 5.35.0
8
- app_file: app.py
 
 
9
  pinned: false
10
- license: mit
11
- short_description: A parsing model for Brazilian Portuguese
 
12
  python_version: 3.11
13
  ---
14
 
15
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
1
  ---
2
  title: Portparser.v2
3
+ emoji: 📚
4
+ colorFrom: red
5
+ colorTo: red
6
  sdk: streamlit
7
+ app_port: 8501
8
+ tags:
9
+ - Universal Dependencies
10
+ - Portuguese
11
  pinned: false
12
+ short_description: Parser for Portuguese texts using UD standards
13
+ license: cc-by-4.0
14
+ sdk_version: 1.46.1
15
  python_version: 3.11
16
  ---
17
 
18
+ # Welcome to Streamlit!
19
+
20
+ Edit `app.py` to customize this app to your heart's desire. :heart:
21
+
22
+ If you have any questions, checkout our [documentation](https://docs.streamlit.io) and [community
23
+ forums](https://discuss.streamlit.io).
app.py ADDED
@@ -0,0 +1,284 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import sys, os, datetime, random, base64, time
2
+ import streamlit as st
3
+ import streamlit.components.v1 as components
4
+ from tempfile import mkdtemp
5
+ from pathlib import Path
6
+ import pandas as pd
7
+ from huggingface_hub import hf_hub_download
8
+
9
+ #-----Initial Parameters----
10
+
11
+ # Must be always False in production. When DEBUG is set to True the interface do not call the parser. Mode to debug interface features in local development.
12
+ DEBUG=False
13
+ # Embedding model. Options are: 'bert-base-portuguese-cased' or 'bert-base-multilingual-uncased'
14
+ MODEL='bert-base-portuguese-cased'
15
+
16
+
17
+ #-----Fuctions-----
18
+
19
+ # Format external files for interface compatibility
20
+ def img_to_bytes(img_path):
21
+ img_bytes = Path(img_path).read_bytes()
22
+ encoded = base64.b64encode(img_bytes).decode()
23
+ return encoded
24
+
25
+ def img_to_html(img_path, img_style='max-width: 100%;'):
26
+ img_html = f"<img src='data:image/png;base64,{img_to_bytes(img_path)}' style='{img_style}'>"
27
+ return img_html
28
+
29
+ # Call parser steps
30
+ def make_sentences(path_raw_text, path_text):
31
+ try:
32
+ #st.text(f'python ./src/portSentencer/portSent.py -o {path_text} -r -l 2048 {path_raw_text}')
33
+ outcome = os.system(f'python ./src/portSentencer/portSent.py -o {path_text} -r -l 2048 {path_raw_text}')
34
+ return f'S'+str(outcome)
35
+ except Exception as e:
36
+ return str(e)
37
+
38
+ def make_conllu(path_text, path_empty_conllu):
39
+ try:
40
+ outcome = os.system(f'python ./src/portTokenizer/portTok.py -o {path_empty_conllu} -m -s S0000 {path_text}')
41
+ return 'T'+str(outcome)
42
+ except Exception as e:
43
+ return str(e)
44
+
45
+ def make_pred(path_empty_conllu, target_directory, model):
46
+ try:
47
+ outcome = os.system(f'python ./src/evalatin2024-latinpipe/latinpipe_evalatin24.py --load {model} --exp {target_directory} --test {path_empty_conllu}')
48
+ return f'P'+str(outcome)
49
+ except Exception as e:
50
+ return str(e)
51
+
52
+ def make_postproc(path_predicted_conllu, path_final_conllu):
53
+ try:
54
+ outcome = os.system(f'python ./src/postproc/postprocess.py -o {path_final_conllu} {path_predicted_conllu}')
55
+ return f'F'+str(outcome)
56
+ except Exception as e:
57
+ return str(e)
58
+
59
+ def get_predictions(path_prediction):
60
+ try:
61
+ with open(path_prediction, 'r') as f:
62
+ st.text(f.read())
63
+ except Exception as e:
64
+ st.text('Resposta: '+e)
65
+
66
+
67
+ def run_pipeline(tmp_dir,code):
68
+
69
+ path_text = tmp_dir+"/"+code+"_input.txt"
70
+ path_empty_conllu = tmp_dir+"/"+code+"_input.conllu"
71
+ #path_predicted_annot = './src/annotation/'+code+'_input.predicted.conllu'
72
+ path_predicted_conllu = tmp_dir+"/"+code+"_input.predicted.conllu"
73
+ path_final_conllu = tmp_dir+"/"+code+"_parsed.conllu"
74
+ #model = '../Portparser.v2-latinpipe-core/model.weights.h5'
75
+ model = hf_hub_download(repo_id="lucelene/Portparser.v2-latinpipe-core",
76
+ filename="model.weights.h5",
77
+ repo_type="model")
78
+ model_op = hf_hub_download(repo_id="lucelene/Portparser.v2-latinpipe-core",
79
+ filename="options.json",
80
+ repo_type="model")
81
+ model_mks = hf_hub_download(repo_id="lucelene/Portparser.v2-latinpipe-core",
82
+ filename="mappings.pkl",
83
+ repo_type="model")
84
+ print("links", model, model_op)
85
+
86
+ # with st.spinner(f'Tok {path_text} into {path_empty_conllu}'):
87
+ with st.spinner('Generating CoNLL-U...'):
88
+ #time.sleep(1)
89
+ try:
90
+ outcome = make_conllu(path_text, path_empty_conllu)
91
+ #st.write("Tok executou!")
92
+ #time.sleep(10)
93
+ except Exception as e:
94
+ st.write("Tok: "+e)
95
+ time.sleep(10)
96
+ # with st.spinner(f'{outcome} - Pred {path_empty_conllu} with {model} into {path_predicted_conllu}'):
97
+ with st.spinner('Predicting annotation...'):
98
+ #time.sleep(1)
99
+ try:
100
+ outcome = make_pred(path_empty_conllu, tmp_dir, model)
101
+ #st.write("Pred executou!")
102
+ #time.sleep(10)
103
+ except Exception as e:
104
+ st.write("Pred: "+e)
105
+ time.sleep(10)
106
+ #infile = open(path_predicted_conllu, "r")
107
+ #empFile = infile.read()
108
+ #infile.close()
109
+ #with st.spinner(path_predicted_conllu+"\n"+empFile):
110
+ #time.sleep(10)
111
+ # with st.spinner(f'{outcome} - Post {path_predicted_conllu} into {path_final_conllu}'):
112
+ with st.spinner('Postprocessing...'):
113
+ #time.sleep(1)
114
+ try:
115
+ outcome = make_postproc(path_predicted_conllu, path_final_conllu)
116
+ #st.write("Postp executou!")
117
+ #time.sleep(10)
118
+ except Exception as e:
119
+ st.write("Postp: "+e)
120
+ time.sleep(10)
121
+ # with st.spinner(f'{outcome} - Done at {path_final_conllu}'):
122
+ with st.spinner('Parsed!'):
123
+ #infile = open(path_final_conllu, "r")
124
+ #empFile = infile.read()
125
+ #infile.close()
126
+ time.sleep(1)
127
+ return path_final_conllu
128
+
129
+ #-----Main Stuff-----
130
+ print("Running the HF server...")
131
+ print(f"Python version: {sys.version_info.major}.{sys.version_info.minor}")
132
+ tmp_dir = mkdtemp()
133
+ #print(tmp_dir)
134
+ code = f'{datetime.datetime.now().strftime("%d%m%Y_%H%M%S%f")+"_"+str(random.randint(0, 9))}'
135
+ #print(code)
136
+ work_dir = './temp/'
137
+ os.chdir('.')
138
+ path_text = f'{tmp_dir}/{code}_input.txt'
139
+ path_final_conllu = f'{work_dir}parsed.conllu' # default to display
140
+ area=0
141
+ with open(path_final_conllu, 'r', encoding='utf-8') as f:content = f.read().split('\n')
142
+
143
+ #-----Interface-----
144
+ with open('./src/arborator-draft/arborator-draft.css','rb') as f: arborator_css = f.read().decode()
145
+ with open('./src/style.css') as f: css = f.read()
146
+
147
+ st.set_page_config(page_title='Portparser v.2', layout="wide")
148
+ st.markdown(f'<style>{css}</style>', unsafe_allow_html=True)
149
+
150
+ # Grid
151
+ rowall = st.columns([2,26,2])
152
+ with rowall[1]:
153
+ row2 = st.columns([6,4])
154
+ # Head
155
+ with row2[0]:
156
+ st.markdown("<p id='logo-position'><b id='logo-title'><i>Portparser</i></b><b id='logo-version'>v.2</b><br><b id='logo-subtitle'>A parsing model for Brazilian Portuguese</b></p>",unsafe_allow_html=True)
157
+ st.markdown("<p class='text'> This is Portparser, a parsing model for Brazilian Portuguese that follows the <a href='https://universaldependencies.org/'>Universal Dependencies (UD)</a> framework.\
158
+ We built our model by using a recently released manually annotated corpus, the Porttinari-base, \
159
+ and we explored different parsing methods and parameters for training. We also test multiple embedding models and parsing methods. \
160
+ Portparser is the result of the best combination achieved in our experiments.</p><p class='text'>This model (version 2) is an evolution of the work previously reported \
161
+ by <a href='https://aclanthology.org/2024.propor-1.41/'>Lopes and Pardo (2024)</a>, and all datasets and full instructions to reproduce our experiments are\
162
+ freely available at the <a href='https://github.com/LuceleneL/Portparser.v2'>Portparser v2 repository</a>. More details about this work may also be found at \
163
+ the <a href='https://sites.google.com/icmc.usp.br/poetisa'>POeTiSA project webpage</a>.</p>",unsafe_allow_html=True)
164
+ with st.expander('To cite Portparser', expanded=False):
165
+ st.code("""
166
+ @inproceedings{lopes2024towards,
167
+ title={Towards Portparser-a highly accurate parsing system for Brazilian Portuguese following the Universal Dependencies framework},
168
+ author={Lopes, Lucelene and Pardo, Thiago},
169
+ booktitle={Proceedings of the 16th International Conference on Computational Processing of Portuguese},
170
+ pages={401--410},
171
+ year={2024}
172
+ }""")
173
+ with row2[1]:
174
+ st.markdown(img_to_html('./src/img/wordcloud_brasil5.png','width:100%; object-position: center top;'), unsafe_allow_html=True)
175
+ # Mode to parse sentence
176
+ mode1, mode2 = st.tabs(['Single sentence', 'Multiple sentences'])
177
+ # 'Single sentence'
178
+ with mode1:
179
+ rowmode1 = st.columns([1,28,1])
180
+ with rowmode1[1]:
181
+ st.write('Write a sentence and run to parse:')
182
+ with st.form("parser"):
183
+ text = st.text_input('Text: ')+' '
184
+ #print("TEXTO",text,"TEXTO")
185
+ #model_selected = MODEL+'-last4'
186
+ submit = st.form_submit_button('Run')
187
+ tab3, tab2, tab1 = st.tabs(["Tree","Table","CoNLL-U"])
188
+ #with open(path_prediction, 'r', encoding='utf-8') as f: content = f.read()
189
+ if submit:
190
+ if not text.strip(): st.text("Can not parse empty text. Write a text above to parse.")
191
+ else:
192
+ try:
193
+ with open(path_text,'w',encoding='utf-8') as f: f.write(text)
194
+ if not DEBUG: path_final_conllu = run_pipeline(tmp_dir,code)
195
+ area=650
196
+ with open(path_final_conllu, 'r', encoding='utf-8') as f:
197
+ content = f.read()
198
+ tab1.text(content)
199
+ content = content.split('\n')
200
+ table = pd.DataFrame([line.split('\t') for line in content[4:]])
201
+ table.columns = ['ID','FORM','LEMMA','UPOS','XPOS','FEATS','HEAD','DEPREL','DEPS','MISC']
202
+ tab2.dataframe(table[:-2], use_container_width=True,hide_index=True)
203
+ except Exception as e:
204
+ st.text('Não deu certo a predição.'+str(e)+repr(e))
205
+ with tab3:
206
+ # Prepare UD tree
207
+ content_str = '\n'.join(content)
208
+ components.html(
209
+ '<style>'+open('./src/arborator-draft/arborator-draft.css','rb').read().decode()+'</style>'+
210
+ #'<style>{arborator_css}</style>'+
211
+ """
212
+ <script language="JavaScript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.js"></script>
213
+ <script src="https://code.jquery.com/jquery-3.2.1.min.js" integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4=" crossorigin="anonymous"></script>
214
+ """+
215
+ '<script>'+open('./src/arborator-draft/arborator-draft.js','rb').read().decode()+'</script>'+
216
+ f'<conll>{content_str}</conll>'+
217
+ '<script>new ArboratorDraft();</script>',height=area)
218
+
219
+ # 'Multiple sentences'
220
+ with mode2:
221
+ rowmode2 = st.columns([1,13,1,14,1])
222
+ predictions = False
223
+ with rowmode2[3]:
224
+ explanation = 'Upload a text file in order to parse multiple sentences. The file must be in a txt format with one sentence per line. \
225
+ In case you have multiple sentences altogether, first select the option "Segment text for me" below, and we split it in lines for you.'
226
+ option1, option2 = 'Text is ready (one sentence per line)','Segment text for me'
227
+ split_option = st.radio(explanation,[option1,option2])
228
+ with rowmode2[1]:
229
+ with st.form("uploadfile_parser"):
230
+ uploaded_file = st.file_uploader("Choose a file")
231
+ submit = st.form_submit_button('Run')
232
+ if submit:
233
+ if uploaded_file is not None:
234
+ # Segment text first
235
+ if split_option==option2:
236
+ path_raw_text = path_text[:-4]+'_raw.txt'
237
+ with open(path_raw_text, 'w') as f: f.write(uploaded_file.read().decode('utf-8'))
238
+ outcome = make_sentences(path_raw_text, path_text)
239
+ # Do not segment text first
240
+ else:
241
+ with open(path_text,'w', encoding="utf-8") as f:f.write(uploaded_file.read().decode('utf-8')+' ')
242
+ if not DEBUG: path_final_conllu = run_pipeline(tmp_dir,code)
243
+ st.download_button(
244
+ label="Download predictions",
245
+ data=open(path_final_conllu, 'r', encoding='utf-8').read(),
246
+ file_name='portparser_generated.conllu')
247
+ predictions = True
248
+ else:
249
+ st.text('Submit a text file to parse.')
250
+ if predictions:
251
+ row1mode2 = st.columns([1,28,1])
252
+ with row1mode2[1]:
253
+ tab1mode2, tab2mode2 = st.tabs(["Sentences","CoNLL-U"])
254
+ tab1mode2.text(open(path_text,"r").read())
255
+ tab2mode2.text(open(path_final_conllu,"r").read())
256
+
257
+ # Foot
258
+ with st.container():
259
+ logorow1 = st.columns([7,4,1,4,1,4,7])
260
+ with logorow1[1]:
261
+ st.markdown("<a href='https://www.icmc.usp.br/'>"+img_to_html('./src/img/icmc.png')+"</a>",unsafe_allow_html=True)
262
+ with logorow1[3]:
263
+ st.markdown("<a href='https://c4ai.inova.usp.br/pt/inicio/'>"+img_to_html('./src/img/c4ia.png')+"</a>",unsafe_allow_html=True)
264
+ with logorow1[5]:
265
+ st.markdown("<a href='https://sites.google.com/view/nilc-usp/'>"+img_to_html('./src/img/nilc-removebg.png','max-width:80%')+"</a>",unsafe_allow_html=True)
266
+ logorow2 = st.columns([7,4,1,4,1,5,7])
267
+ with logorow2[1]:
268
+ st.markdown("<a href='https://inova.usp.br/'>"+img_to_html('./src/img/inova_nobackground.png')+"</a>",unsafe_allow_html=True)
269
+ with logorow2[3]:
270
+ st.markdown("<a href='https://softex.br/'>" + img_to_html('./src/img/softex_nobackground.png') + "</a>",unsafe_allow_html=True)
271
+ with logorow2[5]:
272
+ st.markdown("<a href='https://www.gov.br/mcti/pt-br'>" + img_to_html('./src/img/mcti_nobackground.png') + "</a>",unsafe_allow_html=True)
273
+ logorow3 = st.columns([7,4,1,4,1,4,7])
274
+ with logorow3[3]:
275
+ st.markdown("<a href='https://www.motorola.com.br/'>"+img_to_html('./src/img/motorola_nobackground.png', 'max-width:70%; object-position: center bottom')+"</a>",unsafe_allow_html=True)
276
+ creditrow = st.columns([7,14,7])
277
+ with creditrow[1]:
278
+ st.markdown('<p style="text-align: center;margin-top:10px"> Developed by Lucelene Lopes\
279
+ <a href="https://github.com/LuceleneL"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-github" viewBox="0 0 16 16">\
280
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8"/>\
281
+ </svg></i></a><br>Interface by Ana Carolina Rodrigues\
282
+ <a href="https://github.com/anasampa"><svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="currentColor" class="bi bi-github" viewBox="0 0 16 16">\
283
+ <path d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27s1.36.09 2 .27c1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.01 8.01 0 0 0 16 8c0-4.42-3.58-8-8-8"/>\
284
+ </svg></i></a></p>',unsafe_allow_html=True)
not_used_Dockerfile ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update && apt-get install -y \
6
+ build-essential \
7
+ curl \
8
+ software-properties-common \
9
+ git \
10
+ && rm -rf /var/lib/apt/lists/*
11
+
12
+ COPY requirements.txt ./
13
+ COPY src/ ./src/
14
+
15
+ RUN pip3 install -r requirements.txt
16
+
17
+ EXPOSE 8501
18
+
19
+ HEALTHCHECK CMD curl --fail http://localhost:8501/_stcore/health
20
+
21
+ ENTRYPOINT ["streamlit", "run", "app.py", "--server.port=8501", "--server.address=0.0.0.0"]
requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ keras
2
+ torch
3
+ --extra-index-url=https://download.pytorch.org/whl/cu118
4
+ transformers
5
+ ufal.chu-liu-edmonds
6
+ streamlit
7
+ pandas
8
+ huggingface_hub
runtime.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ python-3.11
src/annotation/setP11.sh ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Install Python3 and Libraries as a local user.
2
+ python_config() {
3
+ export PYTHON_VER="3.11.11"
4
+ export PYTHON_VER_SHORT="$(echo ${PYTHON_VER} | cut -d '.' -f1,2)"
5
+ export PYTHON_REQ="/evalatin2024-latinpipe/requirements.txt"
6
+ cd ~
7
+ rm -rf ~/python && mkdir -p ~/python
8
+ echo "" >> ~/.bashrc
9
+ echo "export PATH=~/python/bin:$PATH" >> ~/.bashrc
10
+ source ~/.bashrc
11
+ wget --quiet --no-check-certificate "https://www.python.org/ftp/python/${PYTHON_VER}/Python-${PYTHON_VER}.tgz"
12
+ tar -zxvf ~/Python-${PYTHON_VER}.tgz 1>/dev/null
13
+ cd ~/Python-${PYTHON_VER}/
14
+ echo "Python ${PYTHON_VER} - Installing in current logged-in user - $(whoami)"
15
+ echo "Python ${PYTHON_VER} - Installation in-progress. Please wait..."
16
+ ./configure --enable-optimizations --prefix=$HOME/python > /dev/null 2>&1;
17
+ echo "Python ${PYTHON_VER} - ETA: upto 5mins. Please wait..."
18
+ make altinstall > /dev/null 2>&1;
19
+ ln -s ~/python/bin/python${PYTHON_VER_SHORT} ~/python/bin/python3
20
+ ln -s ~/python/bin/pip${PYTHON_VER_SHORT} ~/python/bin/pip3
21
+
22
+
23
+ # Install PIP3
24
+ wget --quiet --no-check-certificate https://bootstrap.pypa.io/get-pip.py -O - | python3 - --prefix=$HOME/python
25
+ source ~/.bashrc
26
+ ~/python/bin/pip3 install --upgrade pip
27
+ ~/python/bin/pip3 install --upgrade --no-cache-dir -r ${PYTHON_REQ} --use-pep517
28
+ cd ~ && rm -rf ~/Python-${PYTHON_VER}*
29
+
30
+
31
+ ~/python/bin/python3 --version
32
+ ~/python/bin/pip3 --version
33
+ echo "Python ${PYTHON_VER} - Setup Completed!"
34
+ }
35
+
36
+ # Function Call
37
+ python_config
src/arborator-draft/ArboratorDraft.js ADDED
@@ -0,0 +1 @@
 
 
1
+ new ArboratorDraft();
src/arborator-draft/FileSaver.min.js ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ (function(a,b){if("function"==typeof define&&define.amd)define([],b);else if("undefined"!=typeof exports)b();else{b(),a.FileSaver={exports:{}}.exports}})(this,function(){"use strict";function b(a,b){return"undefined"==typeof b?b={autoBom:!1}:"object"!=typeof b&&(console.warn("Deprecated: Expected third argument to be a object"),b={autoBom:!b}),b.autoBom&&/^\s*(?:text\/\S*|application\/xml|\S*\/\S*\+xml)\s*;.*charset\s*=\s*utf-8/i.test(a.type)?new Blob(["\uFEFF",a],{type:a.type}):a}function c(a,b,c){var d=new XMLHttpRequest;d.open("GET",a),d.responseType="blob",d.onload=function(){g(d.response,b,c)},d.onerror=function(){console.error("could not download file")},d.send()}function d(a){var b=new XMLHttpRequest;b.open("HEAD",a,!1);try{b.send()}catch(a){}return 200<=b.status&&299>=b.status}function e(a){try{a.dispatchEvent(new MouseEvent("click"))}catch(c){var b=document.createEvent("MouseEvents");b.initMouseEvent("click",!0,!0,window,0,0,0,80,20,!1,!1,!1,!1,0,null),a.dispatchEvent(b)}}var f="object"==typeof window&&window.window===window?window:"object"==typeof self&&self.self===self?self:"object"==typeof global&&global.global===global?global:void 0,a=/Macintosh/.test(navigator.userAgent)&&/AppleWebKit/.test(navigator.userAgent)&&!/Safari/.test(navigator.userAgent),g=f.saveAs||("object"!=typeof window||window!==f?function(){}:"download"in HTMLAnchorElement.prototype&&!a?function(b,g,h){var i=f.URL||f.webkitURL,j=document.createElement("a");g=g||b.name||"download",j.download=g,j.rel="noopener","string"==typeof b?(j.href=b,j.origin===location.origin?e(j):d(j.href)?c(b,g,h):e(j,j.target="_blank")):(j.href=i.createObjectURL(b),setTimeout(function(){i.revokeObjectURL(j.href)},4E4),setTimeout(function(){e(j)},0))}:"msSaveOrOpenBlob"in navigator?function(f,g,h){if(g=g||f.name||"download","string"!=typeof f)navigator.msSaveOrOpenBlob(b(f,h),g);else if(d(f))c(f,g,h);else{var i=document.createElement("a");i.href=f,i.target="_blank",setTimeout(function(){e(i)})}}:function(b,d,e,g){if(g=g||open("","_blank"),g&&(g.document.title=g.document.body.innerText="downloading..."),"string"==typeof b)return c(b,d,e);var h="application/octet-stream"===b.type,i=/constructor/i.test(f.HTMLElement)||f.safari,j=/CriOS\/[\d]+/.test(navigator.userAgent);if((j||h&&i||a)&&"undefined"!=typeof FileReader){var k=new FileReader;k.onloadend=function(){var a=k.result;a=j?a:a.replace(/^data:[^;]*;/,"data:attachment/file;"),g?g.location.href=a:location=a,g=null},k.readAsDataURL(b)}else{var l=f.URL||f.webkitURL,m=l.createObjectURL(b);g?g.location=m:location.href=m,g=null,setTimeout(function(){l.revokeObjectURL(m)},4E4)}});f.saveAs=g.saveAs=g,"undefined"!=typeof module&&(module.exports=g)});
2
+
3
+ //# sourceMappingURL=FileSaver.min.js.map
src/arborator-draft/arborator-draft.css ADDED
@@ -0,0 +1,250 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .token {
2
+ font: 18px DejaVu Sans;
3
+ fill: black;
4
+ font-family:sans-serif;
5
+ --wordDistance:33;
6
+ text-align: center;
7
+ }
8
+ .FORM {
9
+ /* font: 18px DejaVu Sans; */
10
+ /* fill: black; */
11
+ /* font-family:sans-serif; */
12
+ --wordDistance:55;
13
+ fill:black;
14
+ text-align: center;
15
+ }
16
+
17
+ .LEMMA {
18
+ font: 15px DejaVu Sans;
19
+ fill: black;
20
+ font-family:sans-serif;
21
+ text-align: center;
22
+ font-style: italic;
23
+ --wordDistance:22;
24
+ }
25
+
26
+ .MISC-Gloss {
27
+ font: 15px DejaVu Sans;
28
+ fill: rgb(124, 96, 86);
29
+ font-family:sans-serif;
30
+ text-align: center;
31
+ font-style: italic;
32
+ --wordDistance:11;
33
+ }
34
+ .UPOS {
35
+ font: 11px DejaVu Sans;
36
+ fill: rgb(80, 29, 125);
37
+ text-align: center;
38
+ --wordDistance:22;
39
+ }
40
+
41
+
42
+
43
+ .DEPREL {
44
+ font: 12px Arial;
45
+ fill: #501d7d;
46
+ font-style: oblique;
47
+ font-family:sans-serif;
48
+ --funcCurveDist:3; /* distance between the function name and the curves highest point */
49
+ }
50
+
51
+
52
+ .lemma {
53
+ font: 15px DejaVu Sans;
54
+ fill: black;
55
+ font-family:sans-serif;
56
+ text-align: center;
57
+ font-style: italic;
58
+ }
59
+
60
+
61
+ .MISC-Gloss {
62
+ font: 15px DejaVu Sans;
63
+ fill: rgb(124, 96, 86);
64
+ font-family:sans-serif;
65
+ text-align: center;
66
+ font-style: italic;
67
+ --wordDistance:11;
68
+ }
69
+
70
+ .xdeprel {
71
+ font: 12px Arial;
72
+ font-style: oblique;
73
+ fill: #21ba45;
74
+ --funcCurveDist:3; /* distance between the function name and the curves highest point */
75
+
76
+ }
77
+
78
+ .xdep {
79
+ stroke: #21ba45;
80
+ fill: none;
81
+ --startOffset: 8;
82
+ --tokDepDist: 15; /* distance between tokens and depdendency relation */
83
+ --depMinHeight: 15; /* minimum height for dependency */
84
+ --wordDistanceFactor: -1; /* distant words get higher curves. this factor fixes how much higher */
85
+ }
86
+
87
+ .arrowhead {
88
+ fill: white;
89
+ stroke: black;
90
+ stroke-width: .8;
91
+ }
92
+
93
+ .arrowheadxdep {
94
+ fill: white;
95
+ stroke: #21ba45;
96
+ stroke-width: .8;
97
+ }
98
+
99
+ .curve {
100
+ stroke: black;
101
+ stroke-width: 1;
102
+ fill: none;
103
+ --startOffset: 8;
104
+ --tokDepDist: 15; /* distance between tokens and depdendency relation */
105
+ --depMinHeight: 15; /* minimum height for dependency */
106
+ --wordDistanceFactor: -1; /* distant words get higher curves. this factor fixes how much higher */
107
+ }
108
+
109
+ .conll {
110
+ display:none; /*toggles to inline*/
111
+ unicode-bidi: embed;
112
+ font-family: monospace;
113
+ white-space: pre;
114
+ margin-bottom: 0.6em;
115
+ border-bottom: 1px solid #aaa;
116
+ padding: 0.5em 0 0.17em 0;
117
+ tab-size: 12;
118
+ background-color: #fff ;
119
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
120
+ }
121
+
122
+ .sentencebox {
123
+ margin-bottom: 0.6em;
124
+ border-bottom: 1px solid lightgrey;
125
+ padding: 0.5em 0 0.17em 0;
126
+ margin-top: 1em;
127
+ }
128
+
129
+ /* Button */
130
+ .button {
131
+ display: inline-block;
132
+ position: relative;
133
+ width: 120px;
134
+ height: 32px;
135
+ line-height: 32px;
136
+ border-radius: 2px;
137
+ font-size: 0.9em;
138
+ background-color: #fff;
139
+ color: #646464;
140
+ cursor:pointer;
141
+ }
142
+
143
+ .button > paper-ripple {
144
+ border-radius: 0px;
145
+ overflow: hidden;
146
+ }
147
+
148
+
149
+ .button.raised {
150
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
151
+ transition-delay: 0.2s;
152
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
153
+ }
154
+
155
+ .button.raised:active {
156
+ box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
157
+ transition-delay: 0s;
158
+ }
159
+
160
+ .center {
161
+ text-align: center;
162
+ }
163
+
164
+
165
+ .svgbox {
166
+ overflow-x: auto;
167
+ }
168
+
169
+
170
+
171
+
172
+ nav {
173
+ display: inline-block;
174
+ vertical-align: middle;
175
+ }
176
+
177
+
178
+
179
+ nav ul {
180
+ font-size: 0;
181
+ list-style: none;
182
+ margin: 0;
183
+ padding: 0;
184
+ /* text-align: center; */
185
+ width: 100%;
186
+
187
+ }
188
+ nav li {
189
+ display: inline-block;
190
+ margin: 0;
191
+ padding: 0;
192
+ position: relative;
193
+ /* min-width: 33%; */
194
+
195
+ }
196
+ nav a {
197
+
198
+ display: block;
199
+ font: normal 16px sans-serif;
200
+ padding-right: 9px;
201
+ text-decoration: none;
202
+ -webkit-transition: all .25s ease;
203
+ -moz-transition: all .25s ease;
204
+ -ms-transition: all .25s ease;
205
+ -o-transition: all .25s ease;
206
+ transition: all .25s ease;
207
+
208
+ }
209
+
210
+ nav li ul li:hover a {
211
+ background: #f5f5f5;
212
+ }
213
+ nav li ul {
214
+
215
+ background: #fff;
216
+ left: 0;
217
+ opacity: 0;
218
+ position: absolute;
219
+ top: 10px;
220
+ visibility: hidden;
221
+ z-index: 1;
222
+ -webkit-transition: all .25s ease;
223
+ -moz-transition: all .25s ease;
224
+ -ms-transition: all .25s ease;
225
+ -o-transition: all .25s ease;
226
+ transition: all .25s ease;
227
+ }
228
+ nav li:hover ul {
229
+ opacity: 1;
230
+ top: 23px;
231
+ visibility: visible;
232
+ }
233
+ nav li ul li {
234
+ width: 130px;
235
+ display: inline-block;
236
+ border-bottom: 1px solid lightgrey;
237
+ background: #fff;
238
+ cursor:pointer;
239
+
240
+ }
241
+ nav li ul a {
242
+ color: #000;
243
+ font: normal 16px/32px sans-serif
244
+ }
245
+ nav li ul a:hover {
246
+ color: #501d7d;
247
+
248
+ text-decoration: none;
249
+ }
250
+
src/arborator-draft/arborator-draft.js ADDED
@@ -0,0 +1,691 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function () {
2
+
3
+ /*!
4
+ * arborator script for dependency drawing
5
+ * version 2.0
6
+ * http://arborator.ilpga.fr/
7
+ *
8
+ * Copyright 2010-2020, Kim Gerdes & Gaël Guibon
9
+ *
10
+ * This program is free software:
11
+ * Licensed under version 3 of the GNU Affero General Public License (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at http://www.gnu.org/licenses/agpl-3.0.html
14
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and limitations under the License.
17
+ *
18
+ */
19
+
20
+ // global variables:
21
+ fontSize = 0; // computed from css value for .token in arborator-draft.css
22
+ svgDefaultHeight = 350;//500;
23
+ el=10; // type of conll (10, 14, or 4), computed in conllNodesToTree
24
+ trees=[]; // list of tree objects
25
+ uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment
26
+ conlltrees=[]; // list of conll strings
27
+ sentences=[]; // list of sentence strings
28
+ theshownfeatures=["FORM", "UPOS", "LEMMA", "MISC.Gloss"]; // recomputed in readConll
29
+ shownmetas=['text_en'];
30
+ showAllConllButton = false;
31
+ progressiveLoading = true; // false to make it load all trees at once (may overload the browser)
32
+ reverseMode = false; // set true for right to left conll
33
+ conlls = {
34
+ 10: {"ID": 0, "FORM":1, "LEMMA": 2, "UPOS": 3, "XPOS":4, "FEATS":5, "HEAD":6, "DEPREL":7, "DEPS":8, "MISC":9},
35
+ 14: {"ID": 0, "FORM":1, "LEMMA": 3, "UPOS": 5, "HEAD":9, "DEPREL":11},
36
+ 4: {"FORM":0, "LEMMA": 0, "UPOS": 1, "HEAD":2, "DEPREL":3}
37
+ };
38
+
39
+ isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; // needed for bezier bounding box bug
40
+ svgIdIndex = 0;
41
+
42
+ // debug:
43
+ log = console.log.bind(console);
44
+
45
+ arborator = `<svg
46
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
47
+ xmlns:cc="http://creativecommons.org/ns#"
48
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
49
+ xmlns:svg="http://www.w3.org/2000/svg"
50
+ xmlns="http://www.w3.org/2000/svg"
51
+ version="1.1"
52
+ viewBox="-4202 0 5704.1939 1840.839"
53
+ style="image-rendering:optimizeQuality;"
54
+ height="13"
55
+ width="27"
56
+ xml:space="preserve">
57
+ <path
58
+ style="fill:none;stroke:#4a2769;stroke-width:128.73750305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;"
59
+ d="m -1890.5398,1002.7933 -1822.5445,615.288 c -261.3344,-190.4146 -424.5469,-433.2903 -424.5469,-661.59345 0,-685.88115 1244.2446,-1296.6446 2780.191,-1296.6446 1534.97478,0 2795.2653,610.76345 2795.2653,1296.6446 0,685.88105 -1252.26757,1244.49535 -2787.2424,1244.49535 -239.9613,0 -490.6091,-19.4301 -718.9123,-43.7176 L -751.94297,618.40481 -882.8496,663.4494" /><path
60
+ style="fill:none;stroke:#dd137b;stroke-width:128.73750305;stroke-miterlimit:4;"
61
+ d="M -864.53567,745.22843 C -964.68477,501.46149 -1354.4152,-183.90675 -1694.5756,-3.2652517 -2014.6556,165.68318 -2049.9732,423.17981 -1871.2632,1084.3717 c 67.0564,232.3776 161.3346,398.0135 238.7197,540.6756" /><path
62
+ style="fill:none;stroke:#4a2769;stroke-width:128.73750305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;"
63
+ d="M -2068.3297,2157.2657 -751.94297,618.40481"
64
+ />
65
+ </svg>`;
66
+
67
+ const defaultcss = `
68
+ .FORM { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; }
69
+ .LEMMA { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; }
70
+ .UPOS { font: 11px DejaVu Sans; fill: rgb(80, 29, 125); text-align: center; }
71
+ .MISC-Gloss {font: 15px DejaVu Sans; fill: rgb(124, 96, 86); font-family:sans-serif; text-align: center; font-style: italic;}
72
+ .DEPREL { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; }
73
+ .arrowhead { fill: white; stroke: black; stroke-width:.8;}
74
+ .arrowheadxdep { fill: white;stroke: #21ba45;stroke-width:.8;}
75
+ .xdep { stroke: #21ba45; stroke-width: 1; fill: none;}
76
+ .curve { stroke: black; stroke-width: 1; fill: none;}
77
+ .xdeprel { font: 12px Arial; font-style: oblique; fill: #21ba45; }
78
+ .svgbox { overflow-x: auto; }`;
79
+
80
+
81
+ // public initialisation function
82
+ this.ArboratorDraft = function(shownfeatures=false, reverse = false, visuMode = 0) {
83
+ // main function called from html file
84
+ if (shownfeatures) {theshownfeatures = shownfeatures;}
85
+ if(reverse) reverseMode = true;
86
+ if(visuMode==0){
87
+ $( ".expander" ).click(function(){
88
+ $(this).next('conll').toggle();});
89
+ readConll();
90
+ }
91
+ else{
92
+ // log('[ArboratorDraft] visumode');
93
+ trees=[];
94
+ uextras=[];
95
+ conlltrees=[];
96
+ sentences=[];
97
+ $('conll').hide();
98
+ refresh( $('#conllarea').text() );
99
+ }
100
+ }
101
+
102
+ // public function
103
+ ArboratorDraft.prototype.emptyThenRefresh = function(content, reverse = false, toggle = false) {
104
+ if(reverse) reverseMode = true; // to set reverse or not
105
+ if(toggle) reverseMode = !reverseMode; // to toggle reverse
106
+ empty().done( refresh( content ) );
107
+ }
108
+
109
+ function refresh(content) {
110
+ $('#svgwell').html('');
111
+ $('#svgwell').append( $("<conll></conll>").attr('id', 'transformhere').text( content ) );
112
+ var conll = d3.selectAll('#transformhere')['_groups'][0][0];
113
+ drawConll(conll);
114
+ return;
115
+ }
116
+
117
+ function empty() {
118
+ var def = new jQuery.Deferred();
119
+ clearTimeout(readInsideConllTimeout);
120
+ treelines = [];
121
+ $('#svgwell').html('');
122
+ def.resolve();
123
+ return def.promise();
124
+ }
125
+
126
+ function progressiveReadConll() {
127
+ // draw each conll tags progressively (only conll tags)
128
+ var conllLoop = d3.selectAll('conll')['_groups'][0]; // need to go out d3js to load it progressively
129
+ var i = 0;
130
+ function waitBetweenElements(range) {
131
+ readConllTimeout = setTimeout(function () {
132
+ drawConll(conllLoop[i]);
133
+ i++;
134
+ if (i < range) {
135
+ waitBetweenElements(range);
136
+ }
137
+ }, 10)
138
+ }
139
+ waitBetweenElements(conllLoop.length);
140
+ }
141
+
142
+ function progressiveReadInsideConll(trees, pnode) {
143
+ // draw each tree INSIDE a conll progressively
144
+ var iWait = 0;
145
+ function waitBetweenElements(range) {
146
+ readInsideConllTimeout = setTimeout(function () {
147
+ pushAndDrawSVG(trees[iWait], pnode);
148
+ iWait++;
149
+ if (iWait < range) waitBetweenElements(range);
150
+ }, 10)
151
+ }
152
+ waitBetweenElements(trees.length);
153
+ }
154
+
155
+ function pushAndDrawSVG(element, pnode) {
156
+ conlltrees.push(element);
157
+ var data=conllNodesToTree(element);
158
+ trees.push(data.tree);
159
+ uextras.push(data.uextra)
160
+ sentences.push(data.sentence)
161
+
162
+ var toggle = true;
163
+ var divsvgbox = pnode.insert('div').attr("class", 'svgbox');
164
+ var divsentbox = divsvgbox.insert('div').attr("class", 'sentencebox')
165
+ divsentbox.insert('nav').html(`
166
+ <ul>
167
+ <li>
168
+ <a>`+arborator+`</a>
169
+ <ul>
170
+ <li id="showconll`+svgIdIndex+`"><a>🗏 Show CoNLL</a></li>
171
+ <li id="pnglink`+svgIdIndex+`"><a>🖼 Save PNG</a></li>
172
+ <li id="svglink`+svgIdIndex+`"><a>🖍️ Save SVG</a></li>
173
+ <li ><a href="https://github.com/Arborator/arborator-draft" target="_blank">🛈 Info Arborator</a></li>
174
+ </ul>
175
+ </li>
176
+ </ul>`);
177
+ $("#pnglink"+svgIdIndex).click(function(){savePng(this.id);});
178
+ $("#svglink"+svgIdIndex).click(function(){saveSvg(this.id);});
179
+ divsentbox.insert('span').html(data.sentence);
180
+ for (shom of shownmetas) {
181
+ if (shom in data.metas)
182
+ if (shom.startsWith("text")) divsentbox.insert('div').html("<i>‘"+data.metas[shom]+"’</i>")
183
+ else divsentbox.insert('div').html(data.metas[shom])
184
+ }
185
+ var thisconll = divsentbox.insert('conll').html(element).attr('class', 'conll');
186
+ $("#showconll"+svgIdIndex).click(function(){
187
+ toggle = !toggle;
188
+ thisconll.style("display", toggle ? "none" : "block");
189
+ $(this.childNodes[0]).html(toggle ? "🗏 Show CoNLL": "🗏 Hide CoNLL") //
190
+ });
191
+ thisconll.style("display", toggle ? "none" : "block");
192
+ draw(divsvgbox, data.tree);
193
+ svgIdIndex=svgIdIndex +1;
194
+ }
195
+
196
+ function readConll() {
197
+ // reads the conll representation of the whole treebank that is in the conll field
198
+ trees=[]; // list of tree objects
199
+ uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment
200
+ conlltrees=[]; // list of conll strings, one string per tree
201
+ sentences=[]; // list of sentence strings, one string per tree
202
+ $('conll').hide(); // to hide the huge conll data
203
+ if(progressiveLoading) {
204
+ progressiveReadConll(); // progressive draw
205
+ }
206
+ else {
207
+ d3.selectAll('conll').each(function(d){ drawConll(this); }); // all at once
208
+ }
209
+ }
210
+
211
+ function drawConll(conllElement) { // for each <conll> section:
212
+ var pnode = d3.select(conllElement.parentNode);
213
+ if(showAllConllButton){
214
+ var conll = d3.select(conllElement).attr("class", 'conll');
215
+ conll.html(conll.html().trim())
216
+ var toggle = false;
217
+ var showHideConll = pnode.insert('div').html('<div class="center" fit>VIEW CONLL</div> <paper-ripple fit></paper-ripple>').attr("class", 'button raised');
218
+ var conllContent = conll.html().trim();
219
+ conll.remove(); // remove the old conll because its place wasn't good
220
+ conll = pnode.insert('conll').html(conllContent).attr('class', 'conll'); //re insert to bind the content
221
+ showHideConll.on("click", ()=>{
222
+ conll.style("display", toggle ? "none" : "block");
223
+ showHideConll.html(toggle ? '<div class="center" fit>VIEW CONLL</div> <paper-ripple fit></paper-ripple>': '<div class="center" fit>HIDE CONLL</div> <paper-ripple fit></paper-ripple>');
224
+ toggle = !toggle;
225
+ });
226
+ }
227
+ treelines = conllElement.textContent.trim().split(/\n\s*\n\s*\n*/);
228
+ if(progressiveLoading) {
229
+ progressiveReadInsideConll(treelines, pnode);
230
+ }
231
+ else {
232
+ for (let singleConll of treelines) { // for each conll tree at once, can block the browser
233
+ pushAndDrawSVG(singleConll, pnode);
234
+ }
235
+ }
236
+ }
237
+
238
+ function conllNodesToTree(treeline) {
239
+ var nodes = treeline.split('\n');
240
+ if(reverseMode) nodes.reverse();
241
+ var tree={};
242
+ var META={}; // sentence features before the actual conll
243
+ var addLines={}; // node position to additional line
244
+ var uextra={}; // todo: check this for reconstruction of conllu
245
+ var lastid=0;
246
+ var skipuntil=0;
247
+ var words=[]
248
+ nodes.forEach(function (nodeline, id)
249
+ { // for each conll line:
250
+ nodeline=nodeline.trim().replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
251
+ if (nodeline.charAt(0) == "#") // META
252
+ {
253
+ var [a,v] = nodeline.substring(1).trim().split("=")
254
+ if (v!=null) var [a,v]=[a.trim(),v.trim()]
255
+ META[a]=v
256
+ return true;
257
+ }
258
+ var elements = nodeline.split('\t');
259
+ el=elements.length;
260
+ if(el > 1)
261
+ {
262
+ if (!(el in conlls) && el>10) el=10;
263
+ if (el > 4) id=elements[conlls[el]["ID"]];
264
+ else if (elements[conlls[el]['FORM']] != "_") id++;
265
+ var form=elements[conlls[el]['FORM']];
266
+ var tokids=id.split("-")
267
+ if (tokids.length == 1) { // simple token
268
+ tree[id]={};
269
+ tree[id]["ID"]=id;
270
+ tree[id]['FORM']=form;
271
+ tree[id]["LEMMA"]=elements[conlls[el]["LEMMA"]];
272
+ tree[id]['UPOS']=elements[conlls[el]['UPOS']];
273
+ tree[id]['HEAD']=parseInt(elements[conlls[el]['HEAD']]);
274
+ tree[id]['DEPREL']=elements[conlls[el]['DEPREL']];
275
+ tree[id]["FEATS"]={};
276
+ tree[id]["DEPS"]={};
277
+ tree[id]["MISC"]={};
278
+ if (id>skipuntil) words.push(form);
279
+ if (el==10) {
280
+ tree[id]["XPOS"] =elements[conlls[el]["XPOS"]];
281
+ tree[id]["FEATS"] = analyzeFeaturestring(elements[conlls[el]["FEATS"]], '=', '|');
282
+ tree[id]["DEPS"] = analyzeFeaturestring(elements[conlls[el]["DEPS"]], ':', '|');
283
+ tree[id]["MISC"] = analyzeFeaturestring(elements[conlls[el]["MISC"]], '=', '|');
284
+ }
285
+ }
286
+ else if (tokids.length == 2){ // n-m type multi-word encoding
287
+ skipuntil = parseInt(tokids[1])
288
+ words.push(elements[conlls[el]['FORM']]);
289
+ if (!(lastid in uextra)) uextra[lastid]=[];
290
+ uextra[lastid].push(nodeline);
291
+ }
292
+ else {
293
+ if (!(lastid in uextra)) uextra[lastid]=[];
294
+ uextra[lastid].push(nodeline);
295
+ }
296
+ }//end if el >1
297
+ else { // bizarre line
298
+ if (!(lastid in addLines)) addLines[lastid]=[];
299
+ addLines[lastid].push(nodeline);
300
+ if (tokids.length == 2){ // n-m type multi-word encoding
301
+ skipuntil = parseInt(tokids[1])
302
+ words.push(elements[conlls[el]['FORM']]);
303
+ }
304
+ tree[id]['HEAD']=parseInt(elements[conlls[el]['HEAD']]); // todo: think about this
305
+ tree[id]['DEPREL']=elements[conlls[el]['DEPREL']];
306
+ }
307
+ lastid=id;
308
+ });
309
+ // now always correcting the META.text feature. if this is not desired, uncomment this line:
310
+ // if {tree:tree, uextra:uextra, sentence:META['text']};
311
+ // got to contstruct the sentence
312
+ var sentence = [];
313
+ words.forEach(function (word, i) {
314
+ sentence.push(word);
315
+ if (!("SpaceAfter" in tree[i+1]["MISC"] && tree[i+1]["MISC"]["SpaceAfter"]=="No" )) sentence.push(" ");
316
+ // if(!reverseMode){
317
+ // if (i+1 in tree && !(("NoSpaceAfter" in tree[i+1]) && tree[i+1]["NoSpaceAfter"]==false)) sentence.push(" ");
318
+ // } else{ sentence.push(word); }
319
+ });
320
+ META['text'] = sentence.join('')
321
+ if ('shownfeatures' in META) {
322
+ theshownfeatures = META['shownfeatures'].split(/,\s*/);
323
+ console.log(theshownfeatures);
324
+ }
325
+ return {tree:tree, uextra:uextra, sentence:META['text'], metas:META};
326
+ }
327
+
328
+ function analyzeFeaturestring(featstr, eq, spl) {
329
+ o={}
330
+ if (featstr.indexOf(eq) > -1){
331
+ featstr.split(spl).forEach(function (f) // for each feature:
332
+ {
333
+ var fs=f.split(eq)
334
+ if (fs.length >=2) {// if it's not just _
335
+ o[fs[0]]=fs.slice(1).join(eq);
336
+ }
337
+ });
338
+ }
339
+ return o;
340
+ }
341
+
342
+ function getSVGPath(startPoint,endPoint,computedStyle,ymove) {
343
+ // startPoint and endPoint are objects for the corresponding nodes
344
+ var tokDepDist = parseInt(computedStyle.getPropertyValue('--tokDepDist'));
345
+ var depMinHeight = parseInt(computedStyle.getPropertyValue('--depMinHeight'));
346
+ var wordDistanceFactor = parseInt(computedStyle.getPropertyValue('--wordDistanceFactor'));
347
+ if(reverseMode) wordDistanceFactor = -Math.abs(wordDistanceFactor);
348
+ var startOffset = parseInt(computedStyle.getPropertyValue('--startOffset'));
349
+ if(reverseMode) startOffset = -Math.abs(startOffset);
350
+ var startOff=(startPoint['ID']-endPoint['ID']>0)?-startOffset:startOffset
351
+ var x1 = startPoint['x']+startPoint['w']/2+startOff;
352
+ var x2 = endPoint['x']+endPoint['w']/2;
353
+ var y1 = svgDefaultHeight-fontSize*2;
354
+ var y2 = svgDefaultHeight-fontSize*2;
355
+ var x1x2=Math.abs(x1-x2)/2;
356
+ var yy = Math.max(y1-x1x2-wordDistanceFactor*Math.abs(endPoint['ID']-startPoint['ID']),-tokDepDist);
357
+ var yy = Math.min(yy,y1)-depMinHeight;
358
+ var cstr="M"+x1+","+y1+" C"+x1+","+yy+" "+x2+","+yy+" "+x2+","+(y2-2+ymove); // -2 so that the arrow is really pointed
359
+ //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point.
360
+ return {cstr:cstr, x0:x1,y0:y1, x1:x1,y1:yy, x2:x2,y2:yy,x3:x2,y3:(y2-2)};
361
+ }
362
+
363
+
364
+ function arrowhead(x,y) {
365
+ // gives path for arrowhead x,y startpoint (end of arrow)
366
+ var size = 5;
367
+ var startpoint = x+","+y; // to move the arrowhead lower: (y+size/3);
368
+ var lefttop = "0,0" +(-size/2)+","+(-size*1.5)+" "+(-size/2)+","+(-size*1.5);
369
+ var righttop = (size/2)+"," +(size/2)+" "+(size/2)+"," +(size/2)+ " "+(size)+",0";
370
+ var arrowPath = "M"+ startpoint+"c"+lefttop+ "c"+righttop+ "z";
371
+ return arrowPath;
372
+ }
373
+
374
+
375
+ function drawDep(tree, id, govid, label, group, smallestY, curvestyle, relstyle, arrowstyle, rootlabels, ymove) {
376
+ var x = tree[id]['x'] + tree[id]['w'] / 2;
377
+ var depLine = group.append("path")
378
+ .attr("class", curvestyle)
379
+ .attr("d", function (dd) {
380
+ if (govid == 0) // sentence root:
381
+ {
382
+ var y = svgDefaultHeight - fontSize * 2;
383
+ return "M" + x + "," + (y - 2 + ymove) + "L" + x + "," + 0;
384
+ }
385
+ else // normal link:
386
+ {
387
+ pathInfo = getSVGPath(tree[govid], tree[id], getComputedStyle(this), ymove);
388
+ return pathInfo.cstr;
389
+ }
390
+ });
391
+ group.append("path")
392
+ .attr("class", arrowstyle)
393
+ .attr("d", function (dd) {
394
+ return arrowhead(x, svgDefaultHeight - fontSize * 2 +ymove);
395
+ });
396
+ var depLineBbox = depLine.node().getBBox();
397
+ if (govid == 0) // root link:
398
+ {
399
+ rootlabels.push(
400
+ group.append('text')
401
+ .attr("class", relstyle)
402
+ .text(label)
403
+ .attr("x", x+2)
404
+ .attr("y", 0)
405
+ );
406
+ }
407
+ else // normal link:
408
+ {
409
+ group.append('text')
410
+ .attr("class", relstyle)
411
+ .text(label)
412
+ .attr("x", function (d) {
413
+ relFontSize = parseInt(getComputedStyle(this).fontSize, 10);
414
+ var w = this.getComputedTextLength(); //<-- length of this node
415
+ return depLineBbox.x + depLineBbox.width / 2 - w / 2;
416
+ })
417
+ .attr("y", function (d) {
418
+ funcCurveDist = parseInt(getComputedStyle(this).getPropertyValue('--funcCurveDist'));
419
+ if (isFirefox) {
420
+ // firefox needs: stackoverflow.com/questions/24809978/calculating-the-bounding-box-of-cubic-bezier-curve
421
+ const { x0, y0, x1, y1, x2, y2, x3, y3 } = pathInfo; // firefox
422
+ y = bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3).min.y - funcCurveDist ;
423
+ return y; // firefox
424
+ }
425
+ else {
426
+ // standard Chrome etc
427
+ y = depLineBbox.y - funcCurveDist;
428
+ return y;
429
+ }
430
+ });
431
+ // if not root, check how high we got:
432
+ var smallY = y - relFontSize;
433
+ smallestY = smallY < smallestY ? smallY : smallestY;
434
+ }
435
+ return 3//smallestY
436
+ }
437
+
438
+
439
+ function draw(div, tree) {
440
+ // draws json tree on svg in div
441
+ var runningWidth = 0;
442
+ var smallestY = svgDefaultHeight;
443
+ var treeArray = $.map(tree, function(value) {return [value];});
444
+ var svg = div.append("svg:svg")
445
+ .attr("width", 1000)
446
+ .attr("height", svgDefaultHeight);
447
+ var group = svg.append("g");
448
+ var rootlabels = [];
449
+ // write tokens:
450
+ if(reverseMode) treeArray.reverse();
451
+ var eachTexts = group.selectAll("text")
452
+ .data(treeArray)
453
+ .enter();
454
+ eachTexts.append('text') // FORM
455
+ .attr("class", "FORM")
456
+ .text(function(d){ return d["FORM"]; } )
457
+ .attr("ID",function(d) { return d["ID"]; } )
458
+ .attr("x", function(d) {
459
+ var w = this.getComputedTextLength();
460
+ wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance'));
461
+ var x = runningWidth; //<-- previous length to return
462
+ runningWidth += w + wordDistance; //<-- total
463
+ tree[d["ID"]]["x"]=x;
464
+ tree[d["ID"]]["w"]=w;
465
+ fontSize = parseInt(getComputedStyle(this).fontSize, 10);
466
+ return x;
467
+ })
468
+ .attr("y", svgDefaultHeight-fontSize);
469
+ svg.attr("width", runningWidth); // adapt svg width
470
+ // draw dependency links:
471
+ group.selectAll("text").each(function(d) { // for each token:
472
+ var id = d3.select(this).attr("ID");
473
+ var govid = tree[id]["HEAD"];
474
+ var label = tree[id]["DEPREL"];
475
+ smallestY = drawDep(tree, id, govid, label, group, smallestY, "curve", "DEPREL","arrowhead", rootlabels, 0); // standard governor relation
476
+ for (var headid in tree[id]["DEPS"]) { // for each governor of extended dependency
477
+ smallestY = drawDep(tree, id, headid, tree[id]["DEPS"][headid], group, smallestY, "xdep", "xdeprel", "arrowheadxdep", rootlabels, -fontSize/2);
478
+ }
479
+ });
480
+ var lastheight = 0;
481
+ var h=0;
482
+
483
+ for (var fea of theshownfeatures) {
484
+ if (fea=="FORM") continue;
485
+ somet=false;
486
+ eachTexts.append('text')
487
+ .attr("class", fea.replace('.', '-'))
488
+ .text(function(d) {var t=fea.split('.').reduce((value,el) => value[el], d); if(!somet && t) somet=true; return t; } )
489
+ .attr("ID",function(d) {return d["ID"];})
490
+ .attr("x", function(d) {
491
+ // var lemmaLength = this.getComputedTextLength();
492
+ // var w = tree[d["ID"]]["w"];
493
+ wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance'));
494
+ h = parseInt(getComputedStyle(this).fontSize, 20);
495
+ return tree[d["ID"]]["x"]; //<-- previous length to return
496
+ })
497
+ .attr("y", svgDefaultHeight-fontSize+lastheight+h)
498
+ .append('title').text(function(d) {return fea.split('.').slice(-1)[0]+": "+fea.split('.').reduce((value,el) => value[el], d); });
499
+ if (somet) lastheight+=h; // found at least once the feature
500
+ }
501
+ // final adjustments:
502
+ for (rl of rootlabels) rl.attr("y",smallestY+fontSize)
503
+ group.attr("transform", "translate(" + 0 + "," + (-smallestY) + ")");
504
+ svg.attr("height", svgDefaultHeight-smallestY+lastheight+fontSize); // adapt svg height
505
+ svg.attr("id", "svg"+svgIdIndex);
506
+ svg.attr("version", '1.1'); // to prepare ddl of svg
507
+ svg.attr("xmlns", "http://www.w3.org/2000/svg"); // to prepare ddl of svg
508
+ }
509
+
510
+
511
+ function bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3) {
512
+ //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point.
513
+ var tvalues = [], xvalues = [], yvalues = [], a, b, c, t, t1, t2, b2ac, sqrtb2ac;
514
+ for (var i = 0; i < 2; ++i) {
515
+ if (i == 0) {
516
+ b = 6 * x0 - 12 * x1 + 6 * x2;
517
+ a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
518
+ c = 3 * x1 - 3 * x0;
519
+ }
520
+ else {
521
+ b = 6 * y0 - 12 * y1 + 6 * y2;
522
+ a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
523
+ c = 3 * y1 - 3 * y0;
524
+ }
525
+ if (Math.abs(a) < 1e-12) {
526
+ if (Math.abs(b) < 1e-12) {
527
+ continue;
528
+ }
529
+ t = -c / b;
530
+ if (0 < t && t < 1) {
531
+ tvalues.push(t);
532
+ }
533
+ continue;
534
+ }
535
+ b2ac = b * b - 4 * c * a;
536
+ if (b2ac < 0) {
537
+ continue;
538
+ }
539
+ sqrtb2ac = Math.sqrt(b2ac);
540
+ t1 = (-b + sqrtb2ac) / (2 * a);
541
+ if (0 < t1 && t1 < 1) {
542
+ tvalues.push(t1);
543
+ }
544
+ t2 = (-b - sqrtb2ac) / (2 * a);
545
+ if (0 < t2 && t2 < 1) {
546
+ tvalues.push(t2);
547
+ }
548
+ }
549
+ var j = tvalues.length, mt;
550
+ while (j--) {
551
+ t = tvalues[j];
552
+ mt = 1 - t;
553
+ xvalues[j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
554
+ yvalues[j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
555
+ }
556
+ xvalues.push(x0,x3);
557
+ yvalues.push(y0,y3);
558
+ return {
559
+ min: {x: Math.min.apply(0, xvalues), y: Math.min.apply(0, yvalues)},
560
+ max: {x: Math.max.apply(0, xvalues), y: Math.max.apply(0, yvalues)}
561
+ };
562
+ }
563
+
564
+ function svg2Data(svg) {
565
+ var tempCSS = document.createElement("style");
566
+ tempCSS.innerHTML = defaultcss;
567
+ svg.insertBefore(tempCSS, svg.firstChild);
568
+ // svg.appendChild(tempCSS);
569
+ return {svg:svg, tempCSS:tempCSS};
570
+ }
571
+
572
+ function png2Data(svg) {
573
+ var canvas = document.createElement('canvas');
574
+ canvas.height = svg.height.baseVal.value*5;
575
+ canvas.width = svg.width.baseVal.value*5;
576
+ var tempCSS = document.createElement("style");
577
+ tempCSS.innerHTML = defaultcss;
578
+ svg.insertBefore(tempCSS, svg.firstChild); // === the missing prepend option
579
+ var data = (new XMLSerializer()).serializeToString(svg);
580
+ canvg(canvas, data, {'scaleWidth':canvas.width,'canvas.height':canvas.height,'ignoreDimensions':true});
581
+ return canvas.toDataURL().replace('data:image/png;base64,','');
582
+ }
583
+
584
+ function savePng(btnId) {
585
+ var id = btnId.replace("pnglink","");
586
+ var canvas = document.createElement('canvas');
587
+ var svg = document.getElementById("svg"+id);
588
+ var sdat = svg2Data(svg);
589
+ canvas.height = svg.height.baseVal.value*5;
590
+ canvas.width = svg.width.baseVal.value*5;
591
+ var ctx = canvas.getContext('2d');
592
+ var data = (new XMLSerializer()).serializeToString(svg);
593
+ var DOMURL = window.URL || window.webkitURL || window;
594
+ var img = new Image();
595
+ var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
596
+ var url = DOMURL.createObjectURL(svgBlob);
597
+
598
+ img.onload = function () {
599
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);//, 0, 0, ctx.width, ctx.height);
600
+ DOMURL.revokeObjectURL(url);
601
+ var imgURI = canvas
602
+ .toDataURL('image/png')
603
+ .replace('image/png', 'image/octet-stream');
604
+ var evt = new MouseEvent('click', {
605
+ view: window,
606
+ bubbles: false,
607
+ cancelable: true
608
+ });
609
+ var a = document.createElement('a');
610
+ a.setAttribute('download', sentences[id].match(/[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]+/g).join(' ').split(" ").slice(0,5).join('_').slice(0,50)+'.png');
611
+ a.setAttribute('href', imgURI );
612
+ a.setAttribute('target', '_blank');
613
+ a.dispatchEvent(evt);
614
+ };
615
+ img.src = url;
616
+
617
+ svg.removeChild(sdat.tempCSS);
618
+ }
619
+
620
+ function saveSvg(btnId) {
621
+ var id = btnId.replace("svglink","");
622
+ var svg = document.getElementById("svg"+id);
623
+ sdat = svg2Data(svg);
624
+ var svgData = svg.outerHTML;
625
+ var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
626
+ var svgUrl = URL.createObjectURL(svgBlob);
627
+ var downloadLink = document.createElement("a");
628
+ downloadLink.href = svgUrl;
629
+ downloadLink.download = sentences[id].match(/[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]+/g).join(' ').split(" ").slice(0,5).join('_').slice(0,50)+".svg";
630
+ document.body.appendChild(downloadLink);
631
+ downloadLink.click();
632
+ document.body.removeChild(downloadLink);
633
+ svg.removeChild(sdat.tempCSS);
634
+ }
635
+
636
+ function exportPngZip() {
637
+ var filename = document.URL? document.URL.substring(document.URL.lastIndexOf('/')+1, document.URL.lastIndexOf('.')):'trees'
638
+ var zip = new JSZip();
639
+ var folder = zip.folder(filename+".PNGfiles");
640
+ var svgList = $('svg');
641
+ $.each( svgList, function( index, svg ){
642
+ if (svg.id) {
643
+ var pngData = png2Data(svg);
644
+ var sent = sentences[svg.id.replace('svg','')].match(/[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]+/g).join(' ').split(" ").slice(0,5).join('_').slice(0,50)
645
+ folder.file('tree'+svg.id.replace('svg','')+'.'+sent+'.png', pngData, {base64: true});
646
+ }
647
+ });
648
+ zip.generateAsync({type:"blob"})
649
+ .then(function(content) {
650
+ saveAs(content, filename + ".png.export.zip");
651
+
652
+ });
653
+ }
654
+
655
+ function exportSvgZip() {
656
+ var zip = new JSZip();
657
+ var folder = zip.folder("svgfiles");
658
+ var svgList = $('svg');
659
+ $.each( svgList, function( index, svg ){
660
+ if (svg.id) {
661
+ var svgData = svg2Data(svg);
662
+ var sent = sentences[svg.id.replace('svg','')].match(/[a-zA-Z\u00c0-\u024f\u1e00-\u1eff]+/g).join(' ').split(" ").slice(0,5).join('_').slice(0,50)
663
+ folder.file('tree'+svg.id.replace('svg','')+'.'+sent+'.svg', svgData.svg.outerHTML);
664
+ }
665
+ });
666
+ // TODO:
667
+ // Add an top-level, arbitrary text file with contents
668
+ // zip.file("Hello.txt", "Hello World\n");
669
+ // Generate a directory within the Zip file structure
670
+ // var img = zip.folder("images");
671
+ // Add a file to the directory, in this case an image with data URI as contents
672
+ // img.file("smile.gif", imgData, {base64: true});
673
+ zip.generateAsync({type:"blob"})
674
+ .then(function(content) {
675
+
676
+ saveAs(content, (document.URL? document.URL.substring(document.URL.lastIndexOf('/')+1, document.URL.lastIndexOf('.')):'trees') + ".svg.export.zip");
677
+ });
678
+ }
679
+
680
+ $("#btnSvgZip").on("click", function (){
681
+ exportSvgZip();
682
+ });
683
+
684
+ $("#btnPngZip").on("click", function (){
685
+ exportPngZip();
686
+ });
687
+
688
+
689
+ }());
690
+
691
+
src/arborator-draft/arborator-draft2.css ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .token {
2
+ font: 18px DejaVu Sans;
3
+ fill: black;
4
+ font-family:sans-serif;
5
+ --wordDistance:33;
6
+ text-align: center;
7
+ }
8
+
9
+ .lemma {
10
+ font: 15px DejaVu Sans;
11
+ fill: black;
12
+ font-family:sans-serif;
13
+ text-align: center;
14
+ font-style: italic;
15
+ }
16
+
17
+ .postag {
18
+ font: 11px DejaVu Sans;
19
+ fill: #E03737;
20
+ /* font-family:sans-serif; */
21
+ text-align: center;
22
+ }
23
+
24
+ .deprel {
25
+ font: 12px Arial;
26
+ fill: #1d2ec1;
27
+ font-style: oblique;
28
+ font-family:sans-serif;
29
+ --funcCurveDist:3; /* distance between the function name and the curves highest point */
30
+ }
31
+
32
+ .arrowhead {
33
+ fill: white;
34
+ stroke: black;
35
+ stroke-width: .8;
36
+ }
37
+
38
+ .curve {
39
+ stroke: black;
40
+ stroke-width: 1;
41
+ fill: none;
42
+ --startOffset: 8;
43
+ --tokDepDist: 15; /* distance between tokens and depdendency relation */
44
+ --depMinHeight: 15; /* minimum height for dependency */
45
+ --wordDistanceFactor: -1; /* distant words get higher curves. this factor fixes how much higher */
46
+ }
47
+
48
+ .conll {
49
+ display:none; /*toggles to inline*/
50
+ unicode-bidi: embed;
51
+ font-family: monospace;
52
+ white-space: pre;
53
+ margin-bottom: 0.6em;
54
+ border-bottom: 1px solid #aaa;
55
+ padding: 0.5em 0 0.17em 0;
56
+ tab-size: 12;
57
+ background-color: #fff ;
58
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
59
+ }
60
+
61
+ .sentencebox {
62
+ margin-bottom: 0.6em;
63
+ border-bottom: 1px solid #aaa;
64
+ padding: 0.5em 0 0.17em 0;
65
+ margin-top: 1em;
66
+ }
67
+
68
+ /* Button */
69
+ .button {
70
+ display: inline-block;
71
+ position: relative;
72
+ width: 120px;
73
+ height: 32px;
74
+ line-height: 32px;
75
+ border-radius: 2px;
76
+ font-size: 0.9em;
77
+ background-color: #fff;
78
+ color: #646464;
79
+ cursor:pointer;
80
+ }
81
+
82
+ .button > paper-ripple {
83
+ border-radius: 2px;
84
+ overflow: hidden;
85
+ }
86
+
87
+
88
+ .button.raised {
89
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 0.2, 1);
90
+ transition-delay: 0.2s;
91
+ box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.26);
92
+ }
93
+
94
+ .button.raised:active {
95
+ box-shadow: 0 8px 17px 0 rgba(0, 0, 0, 0.2);
96
+ transition-delay: 0s;
97
+ }
98
+
99
+ .center {
100
+ text-align: center;
101
+ }
102
+
103
+ /* logo animation transitions */
104
+ .arboratorlogo {
105
+ transition: all 0.4s ease-in-out;
106
+ -webkit-transition: all 0.4s ease-in-out;
107
+ }
108
+
109
+ .arboratorlogo:hover {
110
+ transform: scale(1.1);
111
+ transition: all 0.2s ease-in-out;
112
+ -webkit-transition: all 0.2s ease-in-out;
113
+ opacity: .9;
114
+ }
115
+
116
+ .svgbox {
117
+ overflow-x: auto;
118
+ }
src/arborator-draft/arborator-draft2.js ADDED
@@ -0,0 +1,720 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ (function () {
2
+
3
+ /*!
4
+ * arborator script for dependency drawing
5
+ * version 1.0
6
+ * http://arborator.ilpga.fr/
7
+ *
8
+ * Copyright 2010-2017, Kim Gerdes & Gaël Guibon
9
+ *
10
+ * This program is free software:
11
+ * Licensed under version 3 of the GNU Affero General Public License (the "License");
12
+ * you may not use this file except in compliance with the License.
13
+ * You may obtain a copy of the License at http://www.gnu.org/licenses/agpl-3.0.html
14
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS,
15
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
+ * See the License for the specific language governing permissions and limitations under the License.
17
+ *
18
+ */
19
+
20
+ var drag = d3.drag();
21
+
22
+ // global variables:
23
+ fontSize = 0; // computed from css value for .token in arborator-draft.css
24
+ lemmaHeight = 0;
25
+ posHeight = 0;
26
+ svgDefaultHeight = 500;
27
+ el=10; // type of conll (10, 14, or 4), computed in conllNodesToTree
28
+ trees=[]; // list of tree objects
29
+ uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment TODO: add this to the display
30
+ conlltrees=[]; // list of conll strings
31
+ defaultCat="_"
32
+ shownfeatures=["t", "cat", "lemma","gloss"]; // recomputed in readConll
33
+ progressiveLoading = true; // false to make it load all trees at once (may overload the browser)
34
+ pngBtn = true;
35
+ svgBtn = true;
36
+ reverseMode = false; // set true for right to left conll
37
+ conlls = {
38
+ 10: {"id": 0, "t":1, "lemma": 2, "cat": 3, "xpos":4, "morph":5, "gov":6, "func":7, "xgov":8, "gloss":9},
39
+ 14: {"id": 0, "t":1, "lemma": 3, "cat": 5, "gov":9, "func":11},
40
+ 4: {"t":0, "lemma": 0, "cat": 1, "gov":2, "func":3}
41
+ }
42
+ isFirefox = navigator.userAgent.toLowerCase().indexOf('firefox') > -1; // needed for bezier bounding box bug
43
+
44
+ // debug:
45
+ log = console.log.bind(console);
46
+
47
+ // TODO: add lemmas and pos!!!
48
+ lemmaColor = '#006400';
49
+ posColor = '#9e04de';
50
+
51
+ // base 64 logo of arborator for the link image
52
+ base64Logo = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADQAAAAXCAYAAABEQGxzAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAABtQAAAbUBnmWvHAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAANXSURBVFiFtZhLbA1RGMd/59x7e5XeVrXU45aF9ztCLEQ3gojMwkZiJ7GYRDALhAUJa/FIZjk7EYKWCIMQG0qIx4JIQyREqxWP1uNyH729MxYzreu29zF3xj85mznf+X///8x3Zr4zwrZtqoWqaDXALKClggHwqYLx3jD1wWo1Ca+GVEWbAmwGFGAjECsWK22oyQkyYRsPWRLAbcAEbhim/tmLvooMqYq2HMeAAqwGZLk18USINb1RGjKSn1GLmpzgzOLfXrQBWMBjHHOmYerPyy0oakhVtGbgALANaPWioiEj2fGijmguT5mweThjkGdTsyTDlhe6fPQA54Fjhql/HStglCFV0WLAPmAvJcqpGOKJEOvej2P6r9CouZy0uT47TVdT1ittIRLASeCEYeqJ/Il/SkdVtJVAF3CEKswA1A0Kpv0ebQYgZAnaeqIs7A9XQ52PGI7GLlfzCEYMqYq2FegE4n4ytSRDiBLbsjEtaUyX3YKVIg50utoB15CqaBuBC0Ct3wxNqbGfTj7mDUSY9aN8XIWoBS64Hgj1PR1oBm5RZYkVYlDaLO6PlIyZkJV8q7Vf9dTnJAHcREAA66+du3laAvuBaQGQArDsS6TsN0cA44ZEDJgUVF4cD/sl0BYgKVfmphioLf1a7qvLca81PSPIvC7aJLAsSMZJaWk1pmVRR9+jFh3zkwwF9l74B0sk8C4AIgu4C+y2RHamgINjBaXDNu0LkiQj1fePZfAyDFwFllax2AIeABeBS4apfxyeeNd8uLVQck7A5Xkp+suUo090hoFTwE4q26A2jol2oMMw9b4icWeB9cCi4Qs3Z6forh/yJ7c0PgLHhW3bwx3CHWDiGIE28BDnSXQYpt5blloI8bbp0BNgJcD9eIb78Uxgyoto3GSY+u2RXk5VtFU4phrcgEf8NfHBa4a3kw8dwRZHXzZnMeekgpM+Gilgu2Hq7VDQnKqKthpYC7Qbpt7jJ8vryQdj3Q2i9/L8ZCwn/DCVxAdgi2Hqz4YveD7gVYpdm/dsBXkxK/8Lf9Fu+78YUhVtBfAECKxhc+H9POQXqqK14HzbgujRgjuxVgNV0SI4dT3FB42vfwq+T1oF2AC8ABqBeneMd4eFI/Yb8AXoA7qBNwT41+cPAlA7a3SX2xoAAAAASUVORK5CYII=';
53
+
54
+ svgIdIndex = 0;
55
+
56
+ // public initialisation function
57
+ this.ArboratorDraft = function(visuMode = 0, reverse = false) {
58
+ // main function called from html file
59
+ if(reverse) reverseMode = true;
60
+ if(visuMode==0){
61
+ $( ".expander" ).click(function(){
62
+ log(99,$(this).next('conll'));
63
+ $(this).next('conll').toggle();});
64
+ readConll();
65
+ }else{
66
+ console.log('[ArboratorDraft] visumode');
67
+ trees=[];
68
+ uextras=[];
69
+ conlltrees=[];
70
+ $('conll').hide();
71
+ refresh( $('#conllarea').text() );
72
+ }
73
+ }
74
+
75
+ // public function
76
+ ArboratorDraft.prototype.emptyThenRefresh = function(content, reverse = false, toggle = false) {
77
+ if(reverse) reverseMode = true; // to set reverse or not
78
+ if(toggle) reverseMode = !reverseMode; // to toggle reverse
79
+ empty().done( refresh( content ) );
80
+ }
81
+
82
+
83
+ function refresh(content) {
84
+ $('#svgwell').html('');
85
+ $('#svgwell').append( $("<conll></conll>").attr('id', 'transformhere').text( content ) );
86
+ var conll = d3.selectAll('#transformhere')['_groups'][0][0];
87
+ drawConll(conll);
88
+ return;
89
+ }
90
+
91
+ function sleep(milliseconds) {
92
+ var start = new Date().getTime();
93
+ for (var i = 0; i < 1e7; i++) {
94
+ if ((new Date().getTime() - start) > milliseconds){
95
+ break;
96
+ }
97
+ }
98
+ }
99
+
100
+ function empty() {
101
+ console.log("empty");
102
+ var def = new jQuery.Deferred();
103
+ clearTimeout(readInsideConllTimeout);
104
+ treelines = [];
105
+ $('#svgwell').html('');
106
+ def.resolve();
107
+ return def.promise();
108
+ }
109
+
110
+
111
+ function progressiveReadConll() {
112
+ // draw each conll tags progressively (only conll tags)
113
+ var conllLoop = d3.selectAll('conll')['_groups'][0]; // need to go out d3js to load it progressively
114
+ var i = 0;
115
+ function waitBetweenElements(range) {
116
+ readConllTimeout = setTimeout(function () {
117
+
118
+ drawConll(conllLoop[i]);
119
+ i++;
120
+ if (i < range) {
121
+ waitBetweenElements(range);
122
+ }
123
+ }, 10)
124
+ }
125
+
126
+ waitBetweenElements(conllLoop.length);
127
+ }
128
+
129
+ function progressiveReadInsideConll(trees, pnode) {
130
+ // draw each tree INSIDE a conll progressively
131
+ var iWait = 0;
132
+ function waitBetweenElements(range) {
133
+ readInsideConllTimeout = setTimeout(function () {
134
+
135
+ pushAndDrawSVG(trees[iWait], pnode);
136
+
137
+ iWait++;
138
+ if (iWait < range) {
139
+ waitBetweenElements(range);
140
+ }
141
+ }, 10)
142
+ }
143
+ waitBetweenElements(trees.length);
144
+ }
145
+
146
+ function pushAndDrawSVG(element, pnode) {
147
+ conlltrees.push(element);
148
+ var data=conllNodesToTree(element);
149
+ trees.push(data.tree);
150
+ uextras.push(data.uextra)
151
+
152
+ // add the save png button according to boolean option (default = false)
153
+ if(pngBtn){
154
+ var btn = pnode.insert('button').attr("class", "btn btn-primary").attr("id", "pngbtn"+svgIdIndex).html('Save PNG');
155
+ $("#pngbtn"+svgIdIndex).click(function(){
156
+ console.log("svgIdIndex",this.id);
157
+ savePng(this.id);
158
+ });
159
+ }
160
+
161
+ if(svgBtn){
162
+ var btn = pnode.insert('button').attr("class", "btn btn-success").attr("id", "svgbtn"+svgIdIndex).html('Save SVG');
163
+ $("#svgbtn"+svgIdIndex).click(function(){
164
+ console.log("svgIdIndex",this.id);
165
+ saveSvg(this.id);
166
+ });
167
+ }
168
+
169
+
170
+
171
+ var divsvgbox = pnode.insert('div').attr("class", 'svgbox');
172
+ divsvgbox.insert('div').html(data.sentence).attr("class", 'sentencebox');
173
+ draw(divsvgbox, data.tree);
174
+
175
+ svgIdIndex=svgIdIndex +1;
176
+ }
177
+
178
+
179
+
180
+
181
+
182
+ function readConll() {
183
+ // reads the conll representation of the whole treebank that is in the conll field
184
+
185
+ trees=[]; // list of tree objects
186
+ uextras=[]; // list of comments. each comment is a hashtable position(=line)->comment # TODO: show sentence features!
187
+ conlltrees=[]; // list of conll strings, one string per tree
188
+
189
+ $('conll').hide(); // to hide the huge conll data
190
+
191
+ if(progressiveLoading){
192
+ progressiveReadConll(); // progressive draw
193
+ }else{
194
+ d3.selectAll('conll').each(function(d){ drawConll(this); }); // all at once
195
+ }
196
+
197
+ // TODO: check whether this is useful: adapt which nodes should be shown depending on what we find on the first node
198
+ // TODO : make it faster. This part is really slow
199
+ /*firstnode=trees[0][Math.min.apply(Math,Object.keys(trees[0]))]; // take lowest existing treenode number
200
+ shownfeatures = $.grep(shownfeatures, function (attri,i)
201
+ { // for each shownfeatures :
202
+ if (i < 2 || ((attri in firstnode) && firstnode[attri]!=defaultCat)) {
203
+ // either the first two (token and cat) or non default value:
204
+ return true; // keep it
205
+ }
206
+ return false; // kick it out
207
+ });*/
208
+ }
209
+
210
+ function drawConll(conllElement) { // for each <conll> section:
211
+ var conll = d3.select(conllElement).attr("class", 'conll');
212
+ conll.html(conll.html().trim())
213
+ var pnode = d3.select(conllElement.parentNode);
214
+ var toggle = false;
215
+ pnode.insert('a').html('<img src="'+base64Logo+'" alt="Arborator" title="arborator" class="arboratorlogo">').attr('href', 'https://arborator.github.io/').attr('target', '_blank');
216
+ var showHideConll = pnode.insert('div').html('<div class="center" fit>VIEW CONLL</div> <paper-ripple fit></paper-ripple>').attr("class", 'button raised');
217
+
218
+ // <div class="button raised"> <div class="center" fit>SUBMIT</div> <paper-ripple fit></paper-ripple> </div>
219
+
220
+ var conllContent = conll.html().trim();
221
+ conll.remove(); // remove the old conll because it's place wasn't good
222
+ conll = pnode.insert('conll').html(conllContent).attr('class', 'conll'); //re insert to bind the content
223
+
224
+
225
+ showHideConll.on("click", ()=>{
226
+ log(111,toggle);
227
+ conll.style("display", toggle ? "none" : "block");
228
+ showHideConll.html(toggle ? '<div class="center" fit>VIEW CONLL</div> <paper-ripple fit></paper-ripple>': '<div class="center" fit>HIDE CONLL</div> <paper-ripple fit></paper-ripple>');
229
+ toggle = !toggle;
230
+ });
231
+
232
+
233
+ treelines = conll.html().trim().split(/\n\s*\n\s*\n*/);
234
+
235
+ if(progressiveLoading){
236
+ progressiveReadInsideConll(treelines, pnode);
237
+ }else{
238
+ for (let singleConll of treelines) { // for each conll tree at once, can block the browser
239
+ pushAndDrawSVG(singleConll, pnode);
240
+ }
241
+ }
242
+
243
+ }
244
+
245
+
246
+ function conllNodesToTree(treeline) {
247
+ // reads a conll representation of a single tree TODO: replace jquery by d3
248
+
249
+ var nodes = treeline.split('\n');
250
+ if(reverseMode)nodes.reverse();
251
+ // nodes = nodes.reverse();
252
+ var tree={};
253
+ var uextra={};
254
+ var lastid=0;
255
+ var skipuntil=0;
256
+ var words=[]
257
+ $.each(nodes, function(id,nodeline){ // for each conll line:
258
+ var nodeline=$.trim(nodeline);
259
+ if (nodeline.charAt(0) == "#") {
260
+ if (!(lastid in uextra)) uextra[lastid]=[];
261
+ uextra[lastid].push(nodeline)
262
+ return true;
263
+ }
264
+ var elements = nodeline.split('\t');
265
+ el=elements.length;
266
+
267
+ if (!(el in conlls) && el>10) el=10;
268
+ if (el > 4) id=elements[conlls[el]["id"]];
269
+ else if (elements[conlls[el]["t"]] != "_") id++;
270
+ if (lastid!=id) // needed for the arborator encoding of multiple govs
271
+ {
272
+ var t=elements[conlls[el]["t"]];
273
+ var tokids=id.split("-")
274
+ if (tokids.length == 1) {
275
+ tree[id]={}
276
+ tree[id]["gov"]={};
277
+ tree[id]["t"]=t;
278
+ tree[id]["id"]=id;
279
+ tree[id]["lemma"]=elements[conlls[el]["lemma"]];
280
+ tree[id]["cat"]=elements[conlls[el]["cat"]];
281
+ if (id>skipuntil) words.push(t);
282
+ if (el==10) {
283
+ tree[id]["xpos"]=elements[conlls[el]["xpos"]];
284
+ tree[id]["morph"]=elements[conlls[el]["morph"]];
285
+ tree[id]["gloss"]=elements[conlls[el]["gloss"]];
286
+ if (tree[id]["gloss"]=="SpaceAfter=No"){
287
+ tree[id]["gloss"]="_";
288
+ tree[id]["NoSpaceAfter"]=false;
289
+ }
290
+ var xgov = elements[conlls[el]["xgov"]];
291
+ if (xgov.indexOf(':') > -1){
292
+ var xgovs=xgov.split("|");
293
+ $.each(xgovs, function(ind,xg){
294
+ // for each extra governor line:
295
+ var xgs=xg.split(":")
296
+ if (xgs.length >=2) {
297
+ // if it's not just _
298
+ var gov=xgs[0];
299
+ var func= xgs.slice(1).join(":");
300
+ tree[id]["gov"][gov]=func;
301
+ }
302
+ });
303
+ }
304
+ }
305
+ }
306
+ else if (tokids.length == 2){
307
+ skipuntil = parseInt(tokids[1])
308
+ words.push(elements[conlls[el]["t"]]);
309
+ if (!(lastid in uextra)) uextra[lastid]=[];
310
+ uextra[lastid].push(nodeline)
311
+ }
312
+ else {
313
+ if (!(lastid in uextra)) uextra[lastid]=[];
314
+ uextra[lastid].push(nodeline)
315
+ }
316
+ }
317
+ gov = elements[conlls[el]["gov"]];
318
+ if (gov!="" && gov!="_")
319
+ {
320
+ if (gov==-1)
321
+ {
322
+ gov = elements[conlls[el]["gov"]+1];
323
+ }
324
+ var func = elements[conlls[el]["func"]];
325
+ if (func.indexOf('::') !== -1)
326
+ {
327
+ var stydic = func.substring(func.indexOf("::") + 1);
328
+ func = func.split("::")[0];
329
+ if (stydic!="") funcDic[func] = $.parseJSON(stydic);
330
+ $('#styleconllcheck').prop('checked', true);
331
+ };
332
+ tree[id]["gov"][gov]=func;
333
+
334
+ }
335
+ lastid=id;
336
+ });
337
+
338
+
339
+ var sentence="";
340
+ words.forEach(function (word, i) {
341
+ sentence+=word;
342
+ if(!reverseMode){
343
+ if (i+1 in tree && !(("NoSpaceAfter" in tree[i+1]) && tree[i+1]["NoSpaceAfter"]==false)) sentence+=" ";
344
+ }else{
345
+ sentence+=" ";
346
+ }
347
+ });
348
+ return {tree:tree, uextra:uextra, sentence:sentence};
349
+ }
350
+
351
+
352
+ function getSVGPath(startPoint,endPoint,computedStyle) {
353
+ // startPoint and endPoint are objects for the corresponding nodes
354
+
355
+ var tokDepDist = parseInt(computedStyle.getPropertyValue('--tokDepDist'));
356
+ var depMinHeight = parseInt(computedStyle.getPropertyValue('--depMinHeight'));
357
+ var wordDistanceFactor = parseInt(computedStyle.getPropertyValue('--wordDistanceFactor'));
358
+ if(reverseMode) wordDistanceFactor = -Math.abs(wordDistanceFactor);
359
+ var startOffset = parseInt(computedStyle.getPropertyValue('--startOffset'));
360
+ if(reverseMode) startOffset = -Math.abs(startOffset);
361
+ var startOff=(startPoint['id']-endPoint['id']>0)?-startOffset:startOffset
362
+ var x1 = startPoint['x']+startPoint['w']/2+startOff;
363
+ var x2 = endPoint['x']+endPoint['w']/2;
364
+ var y1 = svgDefaultHeight-fontSize*2;
365
+ var y2 = svgDefaultHeight-fontSize*2;
366
+ var x1x2=Math.abs(x1-x2)/2;
367
+ var yy = Math.max(y1-x1x2-wordDistanceFactor*Math.abs(endPoint['id']-startPoint['id']),-tokDepDist);
368
+ var yy = Math.min(yy,y1)-depMinHeight;
369
+ var cstr="M"+x1+","+y1+" C"+x1+","+yy+" "+x2+","+yy+" "+x2+","+(y2-2); // -2 so that the arrow is really pointed
370
+ //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point.
371
+ return {cstr:cstr, x0:x1,y0:y1, x1:x1,y1:yy, x2:x2,y2:yy,x3:x2,y3:(y2-2)};
372
+ }
373
+
374
+
375
+ function arrowhead(x,y) {
376
+ // gives path for arrowhead x,y startpoint (end of arrow)
377
+ var size = 5;
378
+ var startpoint = x+","+y; // to move the arrowhead lower: (y+size/3);
379
+ var lefttop = "0,0" +(-size/2)+","+(-size*1.5)+" "+(-size/2)+","+(-size*1.5);
380
+ var righttop = (size/2)+"," +(size/2)+" "+(size/2)+"," +(size/2)+ " "+(size)+",0";
381
+ var arrowPath = "M"+ startpoint+"c"+lefttop+ "c"+righttop+ "z";
382
+ return arrowPath;
383
+ }
384
+
385
+
386
+ function draw(div, tree) {
387
+ // draws json tree on svg in div
388
+
389
+ var runningWidth = 0;
390
+ var smallestY = svgDefaultHeight;
391
+ var treeArray = $.map(tree, function(value, index) {return [value];});
392
+ var svg = div.append("svg:svg")
393
+ .attr("width", 1000)
394
+ .attr("height", svgDefaultHeight);
395
+ var group = svg.append("g");
396
+ // write tokens:
397
+ if(reverseMode) treeArray.reverse();
398
+ var eachTexts = group.selectAll("text")
399
+ .data(treeArray)
400
+ .enter();
401
+
402
+
403
+ var runningWidth2 = 0;
404
+
405
+ eachTexts.append('text')
406
+ .attr("class", "token")
407
+ .text(function(d){return d["t"];})
408
+ .attr("id",function(d) {return d["id"];})
409
+ .attr("x", function(d) {
410
+ var w = this.getComputedTextLength();
411
+ wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance'));
412
+ var x = runningWidth; //<-- previous length to return
413
+ runningWidth += w + wordDistance; //<-- total
414
+ tree[d["id"]]["x"]=x;
415
+ tree[d["id"]]["w"]=w;
416
+ fontSize = parseInt(getComputedStyle(this).fontSize, 10);
417
+ return x;
418
+ })
419
+ .attr("y", svgDefaultHeight-fontSize);
420
+
421
+ svg.attr("width", runningWidth); // adapt svg width
422
+
423
+ // draw dependency links
424
+ group.selectAll("text").each(function(d) { // for each token:
425
+ var txt = d3.select(this);
426
+ for (var govid in tree[d3.select(this).attr("id")]["gov"]) { // for each governor
427
+ x=tree[txt.attr("id")]['x']+tree[txt.attr("id")]['w']/2;
428
+ var ligneDep = group.append("path")
429
+ .attr("class", "curve")
430
+ .attr("d", function (dd) {
431
+ if (govid==0) // sentence root:
432
+ {
433
+ var y=svgDefaultHeight-fontSize*2;
434
+ return "M"+x+","+(y-2)+"L"+x+","+0; // -2 so that the arrow is really pointed
435
+ }
436
+ else // normal link:
437
+ {
438
+ pathInfo=getSVGPath(tree[govid],tree[txt.attr("id")], getComputedStyle(this))
439
+ return pathInfo.cstr ;
440
+ }
441
+
442
+ });
443
+ group.append("path")
444
+ .attr("class", "arrowhead")
445
+ .attr("d", function (dd) {
446
+ return arrowhead(x, svgDefaultHeight - fontSize*2);
447
+ });
448
+ var label=tree[d3.select(this).attr("id")]["gov"][govid];
449
+ var depLineBbox=ligneDep.node().getBBox();
450
+
451
+ // TODO: move the "root" label to a good position! (possibly to a group that has to be transformed separately!)
452
+ // TODO: handle mutliple governors!
453
+ if (govid!=0) // normal link:
454
+ {
455
+ group.append('text')
456
+ .attr("class", "deprel")
457
+ .text(function(d){return label})
458
+ .attr("x", function(d) {
459
+ relFontSize = parseInt(getComputedStyle(this).fontSize, 10);
460
+ var w = this.getComputedTextLength(); //<-- length of this node
461
+ return depLineBbox.x + depLineBbox.width/2 - w/2})
462
+ .attr("y", function(d) {
463
+ funcCurveDist = parseInt(getComputedStyle(this).getPropertyValue('--funcCurveDist'));
464
+ if (isFirefox)
465
+ {
466
+ // firefox needs: stackoverflow.com/questions/24809978/calculating-the-bounding-box-of-cubic-bezier-curve
467
+ const {x0, y0, x1, y1, x2, y2, x3, y3} = pathInfo // firefox
468
+ y = bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3).min.y-funcCurveDist;
469
+ return y; // firefox
470
+ }
471
+ else
472
+ {
473
+ // standard Chrome etc
474
+ y = depLineBbox.y-funcCurveDist
475
+ return y;
476
+ }
477
+ })
478
+ // if not root, check how high we got:
479
+ var smallY = y-relFontSize
480
+ smallestY = smallY < smallestY ? smallY : smallestY;
481
+
482
+ }
483
+ }
484
+ // txt.on("click", started);
485
+ txt.on("drag", function(d){console.log('draggg')});
486
+ });
487
+
488
+
489
+ // write lemmas
490
+ eachTexts.append('text')
491
+ .attr("class", "lemma")
492
+ .text(function(d){return d["lemma"];})
493
+ .attr("id",function(d) {return d["id"];})
494
+ .attr("x", function(d) {
495
+ var lemmaLength = this.getComputedTextLength();
496
+ var w = tree[d["id"]]["w"];
497
+ wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance'));
498
+ var x = tree[d["id"]]["x"] ; //<-- previous length to return
499
+ lemmaHeight = parseInt(getComputedStyle(this).fontSize, 20);
500
+ return x;
501
+ })
502
+ .attr("y", svgDefaultHeight-fontSize+lemmaHeight);
503
+
504
+ // write pos
505
+ eachTexts.append('text')
506
+ .attr("class", "postag")
507
+ .text(function(d){return d["cat"];})
508
+ .attr("id",function(d) {return d["id"];})
509
+ .attr("x", function(d) {
510
+ var posLength = this.getComputedTextLength();
511
+ var w = tree[d["id"]]["w"];
512
+ wordDistance = parseInt(getComputedStyle(this).getPropertyValue('--wordDistance'));
513
+ if(posLength>w+10){
514
+ var x = tree[d["id"]]["x"] - posLength/3 ; //<-- previous length to return
515
+ }else{
516
+ var x = tree[d["id"]]["x"] ; //<-- previous length to return
517
+ }
518
+ posHeight = parseInt(getComputedStyle(this).fontSize, 20);
519
+ return x;
520
+ })
521
+ .attr("y", svgDefaultHeight-fontSize+lemmaHeight+posHeight);
522
+
523
+
524
+ group.attr("transform", "translate(" + 0 + "," + (-smallestY) + ")");
525
+ svg.attr("height", svgDefaultHeight-smallestY+posHeight+lemmaHeight+fontSize); // adapt svg height
526
+
527
+ svg.attr("id", "svg"+svgIdIndex);
528
+ svg.attr("version", '1.1'); // to prepare ddl of svg
529
+ svg.attr("xmlns", "http://www.w3.org/2000/svg"); // to prepare ddl of svg
530
+ }
531
+
532
+
533
+ //(x0,y0) is start point; (x1,y1),(x2,y2) is control points; (x3,y3) is end point.
534
+ function bezierMinMax(x0, y0, x1, y1, x2, y2, x3, y3) {
535
+ var tvalues = [], xvalues = [], yvalues = [],
536
+ a, b, c, t, t1, t2, b2ac, sqrtb2ac;
537
+ for (var i = 0; i < 2; ++i) {
538
+ if (i == 0) {
539
+ b = 6 * x0 - 12 * x1 + 6 * x2;
540
+ a = -3 * x0 + 9 * x1 - 9 * x2 + 3 * x3;
541
+ c = 3 * x1 - 3 * x0;
542
+ } else {
543
+ b = 6 * y0 - 12 * y1 + 6 * y2;
544
+ a = -3 * y0 + 9 * y1 - 9 * y2 + 3 * y3;
545
+ c = 3 * y1 - 3 * y0;
546
+ }
547
+ if (Math.abs(a) < 1e-12) {
548
+ if (Math.abs(b) < 1e-12) {
549
+ continue;
550
+ }
551
+ t = -c / b;
552
+ if (0 < t && t < 1) {
553
+ tvalues.push(t);
554
+ }
555
+ continue;
556
+ }
557
+ b2ac = b * b - 4 * c * a;
558
+ if (b2ac < 0) {
559
+ continue;
560
+ }
561
+ sqrtb2ac = Math.sqrt(b2ac);
562
+ t1 = (-b + sqrtb2ac) / (2 * a);
563
+ if (0 < t1 && t1 < 1) {
564
+ tvalues.push(t1);
565
+ }
566
+ t2 = (-b - sqrtb2ac) / (2 * a);
567
+ if (0 < t2 && t2 < 1) {
568
+ tvalues.push(t2);
569
+ }
570
+ }
571
+
572
+ var j = tvalues.length, mt;
573
+ while (j--) {
574
+ t = tvalues[j];
575
+ mt = 1 - t;
576
+ xvalues[j] = (mt * mt * mt * x0) + (3 * mt * mt * t * x1) + (3 * mt * t * t * x2) + (t * t * t * x3);
577
+ yvalues[j] = (mt * mt * mt * y0) + (3 * mt * mt * t * y1) + (3 * mt * t * t * y2) + (t * t * t * y3);
578
+ }
579
+
580
+ xvalues.push(x0,x3);
581
+ yvalues.push(y0,y3);
582
+
583
+ return {
584
+ min: {x: Math.min.apply(0, xvalues), y: Math.min.apply(0, yvalues)},
585
+ max: {x: Math.max.apply(0, xvalues), y: Math.max.apply(0, yvalues)}
586
+ };
587
+ }
588
+
589
+ function svg2Data(svg) {
590
+ var tempCSS = document.createElement("style");
591
+ tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none; .arboratorlogo { transition: all 0.4s ease-in-out; -webkit-transition: all 0.4s ease-in-out; } .arboratorlogo:hover { transform: scale(1.1); transition: all 0.2s ease-in-out; -webkit-transition: all 0.2s ease-in-out; opacity: .9; } .svgbox { overflow-x: auto; }"';
592
+ svg.appendChild(tempCSS);
593
+ return svg.outerHTML;
594
+ }
595
+
596
+ function png2Data(svg) {
597
+ var canvas = document.createElement('canvas');
598
+ var tempCSS = document.createElement("style");
599
+ tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none;}';
600
+ svg.insertBefore(tempCSS, svg.firstChild); // === the missing prepend option
601
+
602
+ var bb = svg.getBBox();
603
+ // canvas.height = bb.height*5;
604
+ // canvas.width = bb.width*5;
605
+ // svg.width = svg.width*3;
606
+ // svg.height = svg.height*3;
607
+ // svg.setAttribute('width', bb.width*5);
608
+ // svg.setAttribute('height', bb.height*5);
609
+ var data = (new XMLSerializer()).serializeToString(svg);
610
+ console.log('svgData', data);
611
+ canvg(canvas, data);
612
+ return canvas.toDataURL().replace('data:image/png;base64,','');
613
+
614
+ }
615
+
616
+ function savePng(btnId) {
617
+ var id = btnId.replace("pngbtn","");
618
+ var canvas = document.createElement('canvas');
619
+ var tempCSS = document.createElement("style");
620
+ tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none;}';
621
+ var svg = document.getElementById("svg"+id);
622
+ svg.appendChild(tempCSS);
623
+ var bb = svg.getBBox();
624
+ canvas.height = bb.height*5;
625
+ canvas.width = bb.width*5;
626
+ var ctx = canvas.getContext('2d');
627
+ var data = (new XMLSerializer()).serializeToString(svg);
628
+ var DOMURL = window.URL || window.webkitURL || window;
629
+ var img = new Image();
630
+ var svgBlob = new Blob([data], {type: 'image/svg+xml;charset=utf-8'});
631
+ var url = DOMURL.createObjectURL(svgBlob);
632
+ img.onload = function () {
633
+ ctx.drawImage(img, 0, 0, canvas.width, canvas.height);//, 0, 0, ctx.width, ctx.height);
634
+ DOMURL.revokeObjectURL(url);
635
+ var imgURI = canvas
636
+ .toDataURL('image/png')
637
+ .replace('image/png', 'image/octet-stream');
638
+ var evt = new MouseEvent('click', {
639
+ view: window,
640
+ bubbles: false,
641
+ cancelable: true
642
+ });
643
+ var a = document.createElement('a');
644
+ a.setAttribute('download', 'svg'+id+'.png');
645
+ a.setAttribute('href', imgURI );
646
+ a.setAttribute('target', '_blank');
647
+ a.dispatchEvent(evt);
648
+ };
649
+ img.src = url;
650
+ }
651
+
652
+ function saveSvg(btnId) {
653
+ console.log(btnId);
654
+ var id = btnId.replace("svgbtn","");
655
+ var canvas = document.createElement('canvas');
656
+ console.log("canvas", canvas);
657
+
658
+
659
+ var tempCSS = document.createElement("style");
660
+ tempCSS.innerHTML = '.token { font: 18px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; } .lemma { font: 15px DejaVu Sans; fill: black; font-family:sans-serif; text-align: center; font-style: italic; } .postag { font: 11px DejaVu Sans; fill: #E03737; text-align: center; } .deprel { font: 12px Arial; fill: #1d2ec1; font-style: oblique; font-family:sans-serif; } .arrowhead { fill: white; stroke: black; stroke-width: .8; } .curve { stroke: black; stroke-width: 1; fill: none; .arboratorlogo { transition: all 0.4s ease-in-out; -webkit-transition: all 0.4s ease-in-out; } .arboratorlogo:hover { transform: scale(1.1); transition: all 0.2s ease-in-out; -webkit-transition: all 0.2s ease-in-out; opacity: .9; } .svgbox { overflow-x: auto; }" width="1140" height="470.1878970357652"';
661
+
662
+ var svg = document.getElementById("svg"+id);
663
+ svg.appendChild(tempCSS);
664
+
665
+ var svgData = svg.outerHTML;
666
+ var svgBlob = new Blob([svgData], {type:"image/svg+xml;charset=utf-8"});
667
+ var svgUrl = URL.createObjectURL(svgBlob);
668
+ var downloadLink = document.createElement("a");
669
+ downloadLink.href = svgUrl;
670
+ downloadLink.download = "treeSvg"+id+".svg";
671
+ document.body.appendChild(downloadLink);
672
+ downloadLink.click();
673
+ document.body.removeChild(downloadLink);
674
+
675
+ }
676
+
677
+
678
+ function exportPngZip() {
679
+ var zip = new JSZip();
680
+ var folder = zip.folder("pngfiles");
681
+ var svgList = $('svg');
682
+ var svgD3List = window.d3.selectAll("svg");
683
+ console.log(2222,svgD3List);
684
+ $.each( svgD3List['_groups'][0], function( index, value ){
685
+ console.log('value', index, value);
686
+ var pngData = png2Data(value);
687
+ folder.file('tree'+value.id+'.png', pngData, {base64: true});
688
+ });
689
+ zip.generateAsync({type:"blob"})
690
+ .then(function(content) {
691
+ saveAs(content, "export.zip");
692
+ });
693
+ }
694
+
695
+ function exportSvgZip() {
696
+ var zip = new JSZip();
697
+ var folder = zip.folder("svgfiles");
698
+ var svgList = $('svg');
699
+ $.each( svgList, function( index, value ){
700
+ var svgData = svg2Data(value);
701
+ folder.file('tree'+svg.id+'.svg', svgData);
702
+ });
703
+
704
+ zip.generateAsync({type:"blob"})
705
+ .then(function(content) {
706
+ saveAs(content, "export.zip");
707
+ });
708
+ }
709
+
710
+ $("#btnSvgZip").on("click", function (){
711
+ exportSvgZip();
712
+ });
713
+
714
+ $("#btnPngZip").on("click", function (){
715
+ exportPngZip();
716
+ });
717
+
718
+
719
+ }());
720
+
src/arborator-draft/arborator.svg ADDED
src/arborator-draft/bootstrap.min.css ADDED
The diff for this file is too large to render. See raw diff
 
src/arborator-draft/canvg.js ADDED
The diff for this file is too large to render. See raw diff
 
src/arborator-draft/d3.js ADDED
The diff for this file is too large to render. See raw diff
 
src/arborator-draft/example_arborator-draft.html ADDED
@@ -0,0 +1,198 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!DOCTYPE HTML>
2
+
3
+ <html>
4
+
5
+ <head>
6
+ <meta charset="UTF-8" />
7
+ <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
8
+ <link rel="stylesheet" href="bootstrap.min.css">
9
+ <link rel="stylesheet" href="arborator-draft.css" type="text/css" />
10
+ <title>Arborator Draft - Example of visualization of CoNLL-U data</title>
11
+ </head>
12
+
13
+ <body>
14
+ <div class="container">
15
+
16
+ <div style="text-align: center;">
17
+ <svg
18
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
19
+ xmlns:cc="http://creativecommons.org/ns#"
20
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
21
+ xmlns:svg="http://www.w3.org/2000/svg"
22
+ xmlns="http://www.w3.org/2000/svg"
23
+ version="1.1"
24
+ viewBox="-4202 0 5704.1939 1840.839"
25
+ style="image-rendering:optimizeQuality;"
26
+ height="130"
27
+ width="270"
28
+ xml:space="preserve">
29
+ <path
30
+ style="fill:none;stroke:#4a2769;stroke-width:128.73750305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;"
31
+ d="m -1890.5398,1002.7933 -1822.5445,615.288 c -261.3344,-190.4146 -424.5469,-433.2903 -424.5469,-661.59345 0,-685.88115 1244.2446,-1296.6446 2780.191,-1296.6446 1534.97478,0 2795.2653,610.76345 2795.2653,1296.6446 0,685.88105 -1252.26757,1244.49535 -2787.2424,1244.49535 -239.9613,0 -490.6091,-19.4301 -718.9123,-43.7176 L -751.94297,618.40481 -882.8496,663.4494" /><path
32
+ style="fill:none;stroke:#dd137b;stroke-width:128.73750305;stroke-miterlimit:4;"
33
+ d="M -864.53567,745.22843 C -964.68477,501.46149 -1354.4152,-183.90675 -1694.5756,-3.2652517 -2014.6556,165.68318 -2049.9732,423.17981 -1871.2632,1084.3717 c 67.0564,232.3776 161.3346,398.0135 238.7197,540.6756" /><path
34
+ style="fill:none;stroke:#4a2769;stroke-width:128.73750305;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;"
35
+ d="M -2068.3297,2157.2657 -751.94297,618.40481"
36
+ />
37
+ </svg>
38
+ </div>
39
+ <div class="row" style="margin-top: 15px;">
40
+ <div class="panel panel-primary" style="border-color: #4a2769;">
41
+ <div class="panel-heading" style="background-color: #4a2769;"><h2 >It's easy to add dependency graphs to your web page</h2></div>
42
+ <div class="panel-body">
43
+
44
+ <ol>
45
+ <li> <strong>Simply put the CoNLL-U data between &lt;conll&gt; tags where you want to show the dependency graph.</strong></li>
46
+ <li><strong>Import arborator-draft.css, arborator-draft.js, d3.js, and jquery.</strong></li>
47
+ <li><strong>Add this in the end of your html page:</strong></li>
48
+ </ol>
49
+
50
+
51
+ <pre><code> window.onload = function () {
52
+ new ArboratorDraft(); // START
53
+ }</code></pre>
54
+ <p><strong>Automatically, the CoNLL-U data will be transformed into beautiful dependency graphs!</strong></p>
55
+
56
+ <p>Graphical options are in arborator-draft.css</p>
57
+ <p>If you want to generally modify which features are shown, modify these lines in the arborator-draft.js:</p>
58
+ <pre><code> shownfeatures=["FORM", "UPOS", "LEMMA", "MISC.Gloss"];
59
+ shownmetas=['text_en']</code></pre>
60
+ <p>If you want to temporarily modify which features are shown, add the shownfeatures attribute to the meta-features of the conll representations, and provide the list of features separated by commas. Morphosyntactic features must be prefixed by FEATS. and miscellaneous features by MISC. as in:</p>
61
+ <pre><code># shownfeatures = FORM, UPOS, LEMMA, MISC.Gloss, FEATS.ExtPos, FEATS.PhraseType, FEATS.InTitle
62
+ </code></pre>
63
+
64
+ <p>If you want to have a button to show the complete conll data (not only per tree), change <code>showAllConllButton</code> to true</p>
65
+ <p>If you want to add those two blue buttons just below to your page, which allow to download the complete set of svg or png images in a zip, add <code>jszip.min.js</code> and <code>FileSaver.min.js</code> to the imports</p>
66
+
67
+ <hr/>
68
+ <p>Please admire the speed of the non-blocking rendering in <a href="speedtest.separateConllTags.html">this file with many separate CoNLL nodes</a> and <a href="speedtest.oneBigConllTag.html">that file with one very long CoNLL node</a></p>
69
+ <p>Todo:
70
+ <ul>
71
+ <li>add sound player if sound_url is present.</li>
72
+ <li>For SVG and PNG download, update automatically the information from the .css file, instead of copying it into the code as defaultcss. See problem at https://stackoverflow.com/questions/3211536/accessing-cross-domain-style-sheet-with-cssrules</li>
73
+ <li>When hanging back in the conll node, fix the order with the neighbors, so that a surrounding div becomes unnecessary.</li>
74
+
75
+ </ul> </p>
76
+
77
+ </div>
78
+ <div class="panel-footer">
79
+ <button id="btnSvgZip" class="btn btn-primary" style="background-color: #4a2769; border-color: #4a2769;">Export SVG files in Zip</button>
80
+ <button id="btnPngZip" class="btn btn-primary" style="background-color: #4a2769; border-color: #4a2769;">Export PNG files in Zip</button>
81
+ </div>
82
+ </div>
83
+ </div>
84
+
85
+ <div class="row">
86
+ <div class="panel panel-primary" style="border-color: #4a2769;">
87
+ <div class="panel-heading" style="background-color: #4a2769; border-color: #4a2769;"><h2>First example of CoNLL-U data surrounded by Conll tags</h2></div>
88
+ <p>Random text before the div containing the conll tag</p>
89
+ <div class="panel-body">
90
+
91
+ <conll>
92
+
93
+ # sent_id = KAD_15_Money-Wahala_MG__22
94
+ # sound_url = http://www.tal.univ-paris3.fr/trameur/iTrameur-naija/mp3/KAD_15_Money-Wahala_MG.mp3
95
+ # speaker_id = Sp194
96
+ # text = # how { di gene- || generation } go be ?//
97
+ # text_en = How will the next gene… generation be?
98
+ # text_ortho = How di gene-... generation go be?
99
+ # shownfeatures = FORM, UPOS, LEMMA, MISC.Gloss, FEATS.PronType, FEATS.Aspect
100
+ 1 # # PUNCT _ _ 2 punct _ AlignBegin=85160|AlignEnd=85800|Gloss=PUNCT
101
+ 2 how how ADV _ PronType=Int 0 root 10:@mod AlignBegin=85800|AlignEnd=86049|Gloss=how.Q
102
+ 3 { { PUNCT _ _ 5 punct _ AlignBegin=86049|AlignEnd=86079|Gloss=PUNCT
103
+ 4 di the DET _ Definite=Def|PronType=Art 5 det _ AlignBegin=86079|AlignEnd=86230|Gloss=DEF.ART
104
+ 5 gene- X X _ _ 9 subj _ AlignBegin=86230|AlignEnd=86530|Gloss=X
105
+ 6 || || PUNCT _ _ 7 punct _ AlignBegin=86530|AlignEnd=86560|Gloss=PUNCT
106
+ 7 generation generation NOUN _ _ 5 conj:coord _ AlignBegin=86560|AlignEnd=86950|Gloss=generation
107
+ 8 } } PUNCT _ _ 5 punct _ AlignBegin=86950|AlignEnd=86980|Gloss=PUNCT
108
+ 9 go go AUX _ Aspect=Prosp 2 comp:cleft _ AlignBegin=86980|AlignEnd=87110|Gloss=PROSP
109
+ 10 be be VERB _ PartType=Cop 9 comp:aux _ AlignBegin=87110|AlignEnd=87310|Gloss=be
110
+ 11 ?// ?// PUNCT _ _ 2 punct _ AlignBegin=87310|AlignEnd=87340|Gloss=PUNCT
111
+
112
+ 1 l' le DET _ _ 2 spe _ _
113
+ 2 avenir avenir NOM _ _ 3 subj _ _
114
+ 3 dépend dépendre VRB _ _ 0 root _ _
115
+ 4 de de PRE _ _ 3 comp _ _
116
+ 5 notre son DET _ _ 6 spe _ _
117
+ 6 capacité capacité NOM _ _ 4 dep _ _
118
+ 7 à à PRE _ _ 6 dep _ _
119
+ 8 construire construire VNF _ _ 7 dep _ _
120
+ 9 à à PRE _ _ 7 para _ _
121
+ 10 créer créer VNF _ _ 9 dep _ _
122
+ 11 à à PRE _ _ 9 para _ _
123
+ 12 rêver rêver VNF _ _ 11 dep _ _
124
+ 13 ensemble ensemble ADV _ _ 12 ad _ _
125
+ 14 les le DET _ _ 15 spe _ _
126
+ 15 voies voie NOM _ _ 12 comp _ _
127
+ 16 de de PRE _ _ 15 dep _ _
128
+ 17 l' le DET _ _ 18 spe _ _
129
+ 18 aventure aventure NOM _ _ 16 dep _ _
130
+ 19 humaine humain ADJ _ _ 18 dep _ _
131
+ </conll>
132
+
133
+ </div>
134
+ <p>Random text after the div containing the conll tag</p>
135
+ </div>
136
+ </div>
137
+
138
+ <div class="row">
139
+ <div class="panel panel-danger">
140
+ <div class="panel-heading" style="background-color: #dd137b;color:white; border-color: #dd137b;"><h2>Another example of CoNLL-U data surrounded by Conll tags</h2></div>
141
+ <div class="panel-body">
142
+ <conll>
143
+
144
+ # text_en = I wrote the letter with a quill.
145
+ 1 Я ja PRON _ Case=Nom|Number=Sing|Person=1|PronType=Prs 2 nsubj _ Gloss=I
146
+ 2 написал napisat' VERB _ Gender=Masc|Number=Sing|VerbForm=Part|Voice=Act 0 root _ Gloss=wrote
147
+ 3 письмо pis'mo NOUN _ Case=Acc|Gender=Neut|Number=Sing 2 dobj _ Gloss=the-letter
148
+ 4 пером pero NOUN _ Case=Ins|Gender=Neut|Number=Sing 2 nmod _ Gloss=with-a-quill
149
+
150
+ 1 car car COO _ _ 12 mark _ _
151
+ 2 dans dans PRE _ _ 12 periph _ _
152
+ 3 un un DET _ _ 4 spe _ _
153
+ 4 monde monde NOM _ _ 2 dep _ _
154
+ 5 où où PRQ _ _ 9 ad _ _
155
+ 6 rien rien PRO _ _ 8 subj _ _
156
+ 7 n' ne CLN _ _ 8 ad _ _
157
+ 8 est être VRB _ _ 4 dep _ _
158
+ 9 figé figer VPP _ _ 8 aux _ _
159
+ 10 l' le DET _ _ 11 spe _ _
160
+ 11 avenir avenir NOM _ _ 12 subj _ _
161
+ 12 dépend dépendre VRB _ _ 0 root _ _
162
+ 13 de de PRE _ _ 12 comp _ _
163
+ 14 nous lui PRO _ _ 13 dep _ _
164
+ </conll>
165
+ </div>
166
+ </div>
167
+ </div>
168
+ </div>
169
+
170
+ <!--
171
+
172
+
173
+ -->
174
+
175
+ <!-- <script language="JavaScript" type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/d3/4.10.0/d3.js"></script> -->
176
+ <script src="d3.js"></script>
177
+ <!-- <script src="d3-drag.min.js"></script> -->
178
+ <!-- <script src="https://code.jquery.com/jquery-3.2.1.min.js"
179
+ integrity="sha256-hwg4gsxgFZhOsEEamdOYGBf13FyQuiTwlAQgxVSNgt4="
180
+ crossorigin="anonymous"></script> -->
181
+ <script src="jquery-3.2.1.min.js"></script>
182
+ <!-- <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js"></script> -->
183
+ <!-- <script src="bootstrap.min.css"></script> -->
184
+ <script src="FileSaver.min.js"></script>
185
+ <script src="jszip.min.js"></script>
186
+ <!-- <script type="text/javascript" src="rgbcolor.js"></script>
187
+ <script type="text/javascript" src="StackBlur.js"></script> -->
188
+ <script type="text/javascript" src="canvg.js"></script>
189
+ <script language="JavaScript" type="text/javascript" src="arborator-draft.js"></script>
190
+ <script>
191
+
192
+ window.onload = function () {
193
+ new ArboratorDraft(myshownfeatures=["FORM", "UPOS", "LEMMA", "MISC.Gloss"]); // START. myshownfeatures has the standard value here and can be omitted if this is the desired set of features to be shown.
194
+ }
195
+ </script>
196
+ </body>
197
+
198
+ </html>
src/arborator-draft/jquery-3.2.1.min.js ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ /*! jQuery v3.2.1 | (c) JS Foundation and other contributors | jquery.org/license */
2
+ !function(a,b){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){"use strict";var c=[],d=a.document,e=Object.getPrototypeOf,f=c.slice,g=c.concat,h=c.push,i=c.indexOf,j={},k=j.toString,l=j.hasOwnProperty,m=l.toString,n=m.call(Object),o={};function p(a,b){b=b||d;var c=b.createElement("script");c.text=a,b.head.appendChild(c).parentNode.removeChild(c)}var q="3.2.1",r=function(a,b){return new r.fn.init(a,b)},s=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,t=/^-ms-/,u=/-([a-z])/g,v=function(a,b){return b.toUpperCase()};r.fn=r.prototype={jquery:q,constructor:r,length:0,toArray:function(){return f.call(this)},get:function(a){return null==a?f.call(this):a<0?this[a+this.length]:this[a]},pushStack:function(a){var b=r.merge(this.constructor(),a);return b.prevObject=this,b},each:function(a){return r.each(this,a)},map:function(a){return this.pushStack(r.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(f.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(a<0?b:0);return this.pushStack(c>=0&&c<b?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:h,sort:c.sort,splice:c.splice},r.extend=r.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||r.isFunction(g)||(g={}),h===i&&(g=this,h--);h<i;h++)if(null!=(a=arguments[h]))for(b in a)c=g[b],d=a[b],g!==d&&(j&&d&&(r.isPlainObject(d)||(e=Array.isArray(d)))?(e?(e=!1,f=c&&Array.isArray(c)?c:[]):f=c&&r.isPlainObject(c)?c:{},g[b]=r.extend(j,f,d)):void 0!==d&&(g[b]=d));return g},r.extend({expando:"jQuery"+(q+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===r.type(a)},isWindow:function(a){return null!=a&&a===a.window},isNumeric:function(a){var b=r.type(a);return("number"===b||"string"===b)&&!isNaN(a-parseFloat(a))},isPlainObject:function(a){var b,c;return!(!a||"[object Object]"!==k.call(a))&&(!(b=e(a))||(c=l.call(b,"constructor")&&b.constructor,"function"==typeof c&&m.call(c)===n))},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?j[k.call(a)]||"object":typeof a},globalEval:function(a){p(a)},camelCase:function(a){return a.replace(t,"ms-").replace(u,v)},each:function(a,b){var c,d=0;if(w(a)){for(c=a.length;d<c;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(s,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(w(Object(a))?r.merge(c,"string"==typeof a?[a]:a):h.call(c,a)),c},inArray:function(a,b,c){return null==b?-1:i.call(b,a,c)},merge:function(a,b){for(var c=+b.length,d=0,e=a.length;d<c;d++)a[e++]=b[d];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;f<g;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,f=0,h=[];if(w(a))for(d=a.length;f<d;f++)e=b(a[f],f,c),null!=e&&h.push(e);else for(f in a)e=b(a[f],f,c),null!=e&&h.push(e);return g.apply([],h)},guid:1,proxy:function(a,b){var c,d,e;if("string"==typeof b&&(c=a[b],b=a,a=c),r.isFunction(a))return d=f.call(arguments,2),e=function(){return a.apply(b||this,d.concat(f.call(arguments)))},e.guid=a.guid=a.guid||r.guid++,e},now:Date.now,support:o}),"function"==typeof Symbol&&(r.fn[Symbol.iterator]=c[Symbol.iterator]),r.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){j["[object "+b+"]"]=b.toLowerCase()});function w(a){var b=!!a&&"length"in a&&a.length,c=r.type(a);return"function"!==c&&!r.isWindow(a)&&("array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a)}var x=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ha(),z=ha(),A=ha(),B=function(a,b){return a===b&&(l=!0),0},C={}.hasOwnProperty,D=[],E=D.pop,F=D.push,G=D.push,H=D.slice,I=function(a,b){for(var c=0,d=a.length;c<d;c++)if(a[c]===b)return c;return-1},J="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",K="[\\x20\\t\\r\\n\\f]",L="(?:\\\\.|[\\w-]|[^\0-\\xa0])+",M="\\["+K+"*("+L+")(?:"+K+"*([*^$|!~]?=)"+K+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+L+"))|)"+K+"*\\]",N=":("+L+")(?:\\((('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|((?:\\\\.|[^\\\\()[\\]]|"+M+")*)|.*)\\)|)",O=new RegExp(K+"+","g"),P=new RegExp("^"+K+"+|((?:^|[^\\\\])(?:\\\\.)*)"+K+"+$","g"),Q=new RegExp("^"+K+"*,"+K+"*"),R=new RegExp("^"+K+"*([>+~]|"+K+")"+K+"*"),S=new RegExp("="+K+"*([^\\]'\"]*?)"+K+"*\\]","g"),T=new RegExp(N),U=new RegExp("^"+L+"$"),V={ID:new RegExp("^#("+L+")"),CLASS:new RegExp("^\\.("+L+")"),TAG:new RegExp("^("+L+"|[*])"),ATTR:new RegExp("^"+M),PSEUDO:new RegExp("^"+N),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+K+"*(even|odd|(([+-]|)(\\d*)n|)"+K+"*(?:([+-]|)"+K+"*(\\d+)|))"+K+"*\\)|)","i"),bool:new RegExp("^(?:"+J+")$","i"),needsContext:new RegExp("^"+K+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+K+"*((?:-\\d)?\\d*)"+K+"*\\)|)(?=[^-]|$)","i")},W=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,Y=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,$=/[+~]/,_=new RegExp("\\\\([\\da-f]{1,6}"+K+"?|("+K+")|.)","ig"),aa=function(a,b,c){var d="0x"+b-65536;return d!==d||c?b:d<0?String.fromCharCode(d+65536):String.fromCharCode(d>>10|55296,1023&d|56320)},ba=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ca=function(a,b){return b?"\0"===a?"\ufffd":a.slice(0,-1)+"\\"+a.charCodeAt(a.length-1).toString(16)+" ":"\\"+a},da=function(){m()},ea=ta(function(a){return a.disabled===!0&&("form"in a||"label"in a)},{dir:"parentNode",next:"legend"});try{G.apply(D=H.call(v.childNodes),v.childNodes),D[v.childNodes.length].nodeType}catch(fa){G={apply:D.length?function(a,b){F.apply(a,H.call(b))}:function(a,b){var c=a.length,d=0;while(a[c++]=b[d++]);a.length=c-1}}}function ga(a,b,d,e){var f,h,j,k,l,o,r,s=b&&b.ownerDocument,w=b?b.nodeType:9;if(d=d||[],"string"!=typeof a||!a||1!==w&&9!==w&&11!==w)return d;if(!e&&((b?b.ownerDocument||b:v)!==n&&m(b),b=b||n,p)){if(11!==w&&(l=Z.exec(a)))if(f=l[1]){if(9===w){if(!(j=b.getElementById(f)))return d;if(j.id===f)return d.push(j),d}else if(s&&(j=s.getElementById(f))&&t(b,j)&&j.id===f)return d.push(j),d}else{if(l[2])return G.apply(d,b.getElementsByTagName(a)),d;if((f=l[3])&&c.getElementsByClassName&&b.getElementsByClassName)return G.apply(d,b.getElementsByClassName(f)),d}if(c.qsa&&!A[a+" "]&&(!q||!q.test(a))){if(1!==w)s=b,r=a;else if("object"!==b.nodeName.toLowerCase()){(k=b.getAttribute("id"))?k=k.replace(ba,ca):b.setAttribute("id",k=u),o=g(a),h=o.length;while(h--)o[h]="#"+k+" "+sa(o[h]);r=o.join(","),s=$.test(a)&&qa(b.parentNode)||b}if(r)try{return G.apply(d,s.querySelectorAll(r)),d}catch(x){}finally{k===u&&b.removeAttribute("id")}}}return i(a.replace(P,"$1"),b,d,e)}function ha(){var a=[];function b(c,e){return a.push(c+" ")>d.cacheLength&&delete b[a.shift()],b[c+" "]=e}return b}function ia(a){return a[u]=!0,a}function ja(a){var b=n.createElement("fieldset");try{return!!a(b)}catch(c){return!1}finally{b.parentNode&&b.parentNode.removeChild(b),b=null}}function ka(a,b){var c=a.split("|"),e=c.length;while(e--)d.attrHandle[c[e]]=b}function la(a,b){var c=b&&a,d=c&&1===a.nodeType&&1===b.nodeType&&a.sourceIndex-b.sourceIndex;if(d)return d;if(c)while(c=c.nextSibling)if(c===b)return-1;return a?1:-1}function ma(a){return function(b){var c=b.nodeName.toLowerCase();return"input"===c&&b.type===a}}function na(a){return function(b){var c=b.nodeName.toLowerCase();return("input"===c||"button"===c)&&b.type===a}}function oa(a){return function(b){return"form"in b?b.parentNode&&b.disabled===!1?"label"in b?"label"in b.parentNode?b.parentNode.disabled===a:b.disabled===a:b.isDisabled===a||b.isDisabled!==!a&&ea(b)===a:b.disabled===a:"label"in b&&b.disabled===a}}function pa(a){return ia(function(b){return b=+b,ia(function(c,d){var e,f=a([],c.length,b),g=f.length;while(g--)c[e=f[g]]&&(c[e]=!(d[e]=c[e]))})})}function qa(a){return a&&"undefined"!=typeof a.getElementsByTagName&&a}c=ga.support={},f=ga.isXML=function(a){var b=a&&(a.ownerDocument||a).documentElement;return!!b&&"HTML"!==b.nodeName},m=ga.setDocument=function(a){var b,e,g=a?a.ownerDocument||a:v;return g!==n&&9===g.nodeType&&g.documentElement?(n=g,o=n.documentElement,p=!f(n),v!==n&&(e=n.defaultView)&&e.top!==e&&(e.addEventListener?e.addEventListener("unload",da,!1):e.attachEvent&&e.attachEvent("onunload",da)),c.attributes=ja(function(a){return a.className="i",!a.getAttribute("className")}),c.getElementsByTagName=ja(function(a){return a.appendChild(n.createComment("")),!a.getElementsByTagName("*").length}),c.getElementsByClassName=Y.test(n.getElementsByClassName),c.getById=ja(function(a){return o.appendChild(a).id=u,!n.getElementsByName||!n.getElementsByName(u).length}),c.getById?(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){return a.getAttribute("id")===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c=b.getElementById(a);return c?[c]:[]}}):(d.filter.ID=function(a){var b=a.replace(_,aa);return function(a){var c="undefined"!=typeof a.getAttributeNode&&a.getAttributeNode("id");return c&&c.value===b}},d.find.ID=function(a,b){if("undefined"!=typeof b.getElementById&&p){var c,d,e,f=b.getElementById(a);if(f){if(c=f.getAttributeNode("id"),c&&c.value===a)return[f];e=b.getElementsByName(a),d=0;while(f=e[d++])if(c=f.getAttributeNode("id"),c&&c.value===a)return[f]}return[]}}),d.find.TAG=c.getElementsByTagName?function(a,b){return"undefined"!=typeof b.getElementsByTagName?b.getElementsByTagName(a):c.qsa?b.querySelectorAll(a):void 0}:function(a,b){var c,d=[],e=0,f=b.getElementsByTagName(a);if("*"===a){while(c=f[e++])1===c.nodeType&&d.push(c);return d}return f},d.find.CLASS=c.getElementsByClassName&&function(a,b){if("undefined"!=typeof b.getElementsByClassName&&p)return b.getElementsByClassName(a)},r=[],q=[],(c.qsa=Y.test(n.querySelectorAll))&&(ja(function(a){o.appendChild(a).innerHTML="<a id='"+u+"'></a><select id='"+u+"-\r\\' msallowcapture=''><option selected=''></option></select>",a.querySelectorAll("[msallowcapture^='']").length&&q.push("[*^$]="+K+"*(?:''|\"\")"),a.querySelectorAll("[selected]").length||q.push("\\["+K+"*(?:value|"+J+")"),a.querySelectorAll("[id~="+u+"-]").length||q.push("~="),a.querySelectorAll(":checked").length||q.push(":checked"),a.querySelectorAll("a#"+u+"+*").length||q.push(".#.+[+~]")}),ja(function(a){a.innerHTML="<a href='' disabled='disabled'></a><select disabled='disabled'><option/></select>";var b=n.createElement("input");b.setAttribute("type","hidden"),a.appendChild(b).setAttribute("name","D"),a.querySelectorAll("[name=d]").length&&q.push("name"+K+"*[*^$|!~]?="),2!==a.querySelectorAll(":enabled").length&&q.push(":enabled",":disabled"),o.appendChild(a).disabled=!0,2!==a.querySelectorAll(":disabled").length&&q.push(":enabled",":disabled"),a.querySelectorAll("*,:x"),q.push(",.*:")})),(c.matchesSelector=Y.test(s=o.matches||o.webkitMatchesSelector||o.mozMatchesSelector||o.oMatchesSelector||o.msMatchesSelector))&&ja(function(a){c.disconnectedMatch=s.call(a,"*"),s.call(a,"[s!='']:x"),r.push("!=",N)}),q=q.length&&new RegExp(q.join("|")),r=r.length&&new RegExp(r.join("|")),b=Y.test(o.compareDocumentPosition),t=b||Y.test(o.contains)?function(a,b){var c=9===a.nodeType?a.documentElement:a,d=b&&b.parentNode;return a===d||!(!d||1!==d.nodeType||!(c.contains?c.contains(d):a.compareDocumentPosition&&16&a.compareDocumentPosition(d)))}:function(a,b){if(b)while(b=b.parentNode)if(b===a)return!0;return!1},B=b?function(a,b){if(a===b)return l=!0,0;var d=!a.compareDocumentPosition-!b.compareDocumentPosition;return d?d:(d=(a.ownerDocument||a)===(b.ownerDocument||b)?a.compareDocumentPosition(b):1,1&d||!c.sortDetached&&b.compareDocumentPosition(a)===d?a===n||a.ownerDocument===v&&t(v,a)?-1:b===n||b.ownerDocument===v&&t(v,b)?1:k?I(k,a)-I(k,b):0:4&d?-1:1)}:function(a,b){if(a===b)return l=!0,0;var c,d=0,e=a.parentNode,f=b.parentNode,g=[a],h=[b];if(!e||!f)return a===n?-1:b===n?1:e?-1:f?1:k?I(k,a)-I(k,b):0;if(e===f)return la(a,b);c=a;while(c=c.parentNode)g.unshift(c);c=b;while(c=c.parentNode)h.unshift(c);while(g[d]===h[d])d++;return d?la(g[d],h[d]):g[d]===v?-1:h[d]===v?1:0},n):n},ga.matches=function(a,b){return ga(a,null,null,b)},ga.matchesSelector=function(a,b){if((a.ownerDocument||a)!==n&&m(a),b=b.replace(S,"='$1']"),c.matchesSelector&&p&&!A[b+" "]&&(!r||!r.test(b))&&(!q||!q.test(b)))try{var d=s.call(a,b);if(d||c.disconnectedMatch||a.document&&11!==a.document.nodeType)return d}catch(e){}return ga(b,n,null,[a]).length>0},ga.contains=function(a,b){return(a.ownerDocument||a)!==n&&m(a),t(a,b)},ga.attr=function(a,b){(a.ownerDocument||a)!==n&&m(a);var e=d.attrHandle[b.toLowerCase()],f=e&&C.call(d.attrHandle,b.toLowerCase())?e(a,b,!p):void 0;return void 0!==f?f:c.attributes||!p?a.getAttribute(b):(f=a.getAttributeNode(b))&&f.specified?f.value:null},ga.escape=function(a){return(a+"").replace(ba,ca)},ga.error=function(a){throw new Error("Syntax error, unrecognized expression: "+a)},ga.uniqueSort=function(a){var b,d=[],e=0,f=0;if(l=!c.detectDuplicates,k=!c.sortStable&&a.slice(0),a.sort(B),l){while(b=a[f++])b===a[f]&&(e=d.push(f));while(e--)a.splice(d[e],1)}return k=null,a},e=ga.getText=function(a){var b,c="",d=0,f=a.nodeType;if(f){if(1===f||9===f||11===f){if("string"==typeof a.textContent)return a.textContent;for(a=a.firstChild;a;a=a.nextSibling)c+=e(a)}else if(3===f||4===f)return a.nodeValue}else while(b=a[d++])c+=e(b);return c},d=ga.selectors={cacheLength:50,createPseudo:ia,match:V,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(a){return a[1]=a[1].replace(_,aa),a[3]=(a[3]||a[4]||a[5]||"").replace(_,aa),"~="===a[2]&&(a[3]=" "+a[3]+" "),a.slice(0,4)},CHILD:function(a){return a[1]=a[1].toLowerCase(),"nth"===a[1].slice(0,3)?(a[3]||ga.error(a[0]),a[4]=+(a[4]?a[5]+(a[6]||1):2*("even"===a[3]||"odd"===a[3])),a[5]=+(a[7]+a[8]||"odd"===a[3])):a[3]&&ga.error(a[0]),a},PSEUDO:function(a){var b,c=!a[6]&&a[2];return V.CHILD.test(a[0])?null:(a[3]?a[2]=a[4]||a[5]||"":c&&T.test(c)&&(b=g(c,!0))&&(b=c.indexOf(")",c.length-b)-c.length)&&(a[0]=a[0].slice(0,b),a[2]=c.slice(0,b)),a.slice(0,3))}},filter:{TAG:function(a){var b=a.replace(_,aa).toLowerCase();return"*"===a?function(){return!0}:function(a){return a.nodeName&&a.nodeName.toLowerCase()===b}},CLASS:function(a){var b=y[a+" "];return b||(b=new RegExp("(^|"+K+")"+a+"("+K+"|$)"))&&y(a,function(a){return b.test("string"==typeof a.className&&a.className||"undefined"!=typeof a.getAttribute&&a.getAttribute("class")||"")})},ATTR:function(a,b,c){return function(d){var e=ga.attr(d,a);return null==e?"!="===b:!b||(e+="","="===b?e===c:"!="===b?e!==c:"^="===b?c&&0===e.indexOf(c):"*="===b?c&&e.indexOf(c)>-1:"$="===b?c&&e.slice(-c.length)===c:"~="===b?(" "+e.replace(O," ")+" ").indexOf(c)>-1:"|="===b&&(e===c||e.slice(0,c.length+1)===c+"-"))}},CHILD:function(a,b,c,d,e){var f="nth"!==a.slice(0,3),g="last"!==a.slice(-4),h="of-type"===b;return 1===d&&0===e?function(a){return!!a.parentNode}:function(b,c,i){var j,k,l,m,n,o,p=f!==g?"nextSibling":"previousSibling",q=b.parentNode,r=h&&b.nodeName.toLowerCase(),s=!i&&!h,t=!1;if(q){if(f){while(p){m=b;while(m=m[p])if(h?m.nodeName.toLowerCase()===r:1===m.nodeType)return!1;o=p="only"===a&&!o&&"nextSibling"}return!0}if(o=[g?q.firstChild:q.lastChild],g&&s){m=q,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n&&j[2],m=n&&q.childNodes[n];while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if(1===m.nodeType&&++t&&m===b){k[a]=[w,n,t];break}}else if(s&&(m=b,l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),j=k[a]||[],n=j[0]===w&&j[1],t=n),t===!1)while(m=++n&&m&&m[p]||(t=n=0)||o.pop())if((h?m.nodeName.toLowerCase()===r:1===m.nodeType)&&++t&&(s&&(l=m[u]||(m[u]={}),k=l[m.uniqueID]||(l[m.uniqueID]={}),k[a]=[w,t]),m===b))break;return t-=e,t===d||t%d===0&&t/d>=0}}},PSEUDO:function(a,b){var c,e=d.pseudos[a]||d.setFilters[a.toLowerCase()]||ga.error("unsupported pseudo: "+a);return e[u]?e(b):e.length>1?(c=[a,a,"",b],d.setFilters.hasOwnProperty(a.toLowerCase())?ia(function(a,c){var d,f=e(a,b),g=f.length;while(g--)d=I(a,f[g]),a[d]=!(c[d]=f[g])}):function(a){return e(a,0,c)}):e}},pseudos:{not:ia(function(a){var b=[],c=[],d=h(a.replace(P,"$1"));return d[u]?ia(function(a,b,c,e){var f,g=d(a,null,e,[]),h=a.length;while(h--)(f=g[h])&&(a[h]=!(b[h]=f))}):function(a,e,f){return b[0]=a,d(b,null,f,c),b[0]=null,!c.pop()}}),has:ia(function(a){return function(b){return ga(a,b).length>0}}),contains:ia(function(a){return a=a.replace(_,aa),function(b){return(b.textContent||b.innerText||e(b)).indexOf(a)>-1}}),lang:ia(function(a){return U.test(a||"")||ga.error("unsupported lang: "+a),a=a.replace(_,aa).toLowerCase(),function(b){var c;do if(c=p?b.lang:b.getAttribute("xml:lang")||b.getAttribute("lang"))return c=c.toLowerCase(),c===a||0===c.indexOf(a+"-");while((b=b.parentNode)&&1===b.nodeType);return!1}}),target:function(b){var c=a.location&&a.location.hash;return c&&c.slice(1)===b.id},root:function(a){return a===o},focus:function(a){return a===n.activeElement&&(!n.hasFocus||n.hasFocus())&&!!(a.type||a.href||~a.tabIndex)},enabled:oa(!1),disabled:oa(!0),checked:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&!!a.checked||"option"===b&&!!a.selected},selected:function(a){return a.parentNode&&a.parentNode.selectedIndex,a.selected===!0},empty:function(a){for(a=a.firstChild;a;a=a.nextSibling)if(a.nodeType<6)return!1;return!0},parent:function(a){return!d.pseudos.empty(a)},header:function(a){return X.test(a.nodeName)},input:function(a){return W.test(a.nodeName)},button:function(a){var b=a.nodeName.toLowerCase();return"input"===b&&"button"===a.type||"button"===b},text:function(a){var b;return"input"===a.nodeName.toLowerCase()&&"text"===a.type&&(null==(b=a.getAttribute("type"))||"text"===b.toLowerCase())},first:pa(function(){return[0]}),last:pa(function(a,b){return[b-1]}),eq:pa(function(a,b,c){return[c<0?c+b:c]}),even:pa(function(a,b){for(var c=0;c<b;c+=2)a.push(c);return a}),odd:pa(function(a,b){for(var c=1;c<b;c+=2)a.push(c);return a}),lt:pa(function(a,b,c){for(var d=c<0?c+b:c;--d>=0;)a.push(d);return a}),gt:pa(function(a,b,c){for(var d=c<0?c+b:c;++d<b;)a.push(d);return a})}},d.pseudos.nth=d.pseudos.eq;for(b in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})d.pseudos[b]=ma(b);for(b in{submit:!0,reset:!0})d.pseudos[b]=na(b);function ra(){}ra.prototype=d.filters=d.pseudos,d.setFilters=new ra,g=ga.tokenize=function(a,b){var c,e,f,g,h,i,j,k=z[a+" "];if(k)return b?0:k.slice(0);h=a,i=[],j=d.preFilter;while(h){c&&!(e=Q.exec(h))||(e&&(h=h.slice(e[0].length)||h),i.push(f=[])),c=!1,(e=R.exec(h))&&(c=e.shift(),f.push({value:c,type:e[0].replace(P," ")}),h=h.slice(c.length));for(g in d.filter)!(e=V[g].exec(h))||j[g]&&!(e=j[g](e))||(c=e.shift(),f.push({value:c,type:g,matches:e}),h=h.slice(c.length));if(!c)break}return b?h.length:h?ga.error(a):z(a,i).slice(0)};function sa(a){for(var b=0,c=a.length,d="";b<c;b++)d+=a[b].value;return d}function ta(a,b,c){var d=b.dir,e=b.next,f=e||d,g=c&&"parentNode"===f,h=x++;return b.first?function(b,c,e){while(b=b[d])if(1===b.nodeType||g)return a(b,c,e);return!1}:function(b,c,i){var j,k,l,m=[w,h];if(i){while(b=b[d])if((1===b.nodeType||g)&&a(b,c,i))return!0}else while(b=b[d])if(1===b.nodeType||g)if(l=b[u]||(b[u]={}),k=l[b.uniqueID]||(l[b.uniqueID]={}),e&&e===b.nodeName.toLowerCase())b=b[d]||b;else{if((j=k[f])&&j[0]===w&&j[1]===h)return m[2]=j[2];if(k[f]=m,m[2]=a(b,c,i))return!0}return!1}}function ua(a){return a.length>1?function(b,c,d){var e=a.length;while(e--)if(!a[e](b,c,d))return!1;return!0}:a[0]}function va(a,b,c){for(var d=0,e=b.length;d<e;d++)ga(a,b[d],c);return c}function wa(a,b,c,d,e){for(var f,g=[],h=0,i=a.length,j=null!=b;h<i;h++)(f=a[h])&&(c&&!c(f,d,e)||(g.push(f),j&&b.push(h)));return g}function xa(a,b,c,d,e,f){return d&&!d[u]&&(d=xa(d)),e&&!e[u]&&(e=xa(e,f)),ia(function(f,g,h,i){var j,k,l,m=[],n=[],o=g.length,p=f||va(b||"*",h.nodeType?[h]:h,[]),q=!a||!f&&b?p:wa(p,m,a,h,i),r=c?e||(f?a:o||d)?[]:g:q;if(c&&c(q,r,h,i),d){j=wa(r,n),d(j,[],h,i),k=j.length;while(k--)(l=j[k])&&(r[n[k]]=!(q[n[k]]=l))}if(f){if(e||a){if(e){j=[],k=r.length;while(k--)(l=r[k])&&j.push(q[k]=l);e(null,r=[],j,i)}k=r.length;while(k--)(l=r[k])&&(j=e?I(f,l):m[k])>-1&&(f[j]=!(g[j]=l))}}else r=wa(r===g?r.splice(o,r.length):r),e?e(null,g,r,i):G.apply(g,r)})}function ya(a){for(var b,c,e,f=a.length,g=d.relative[a[0].type],h=g||d.relative[" "],i=g?1:0,k=ta(function(a){return a===b},h,!0),l=ta(function(a){return I(b,a)>-1},h,!0),m=[function(a,c,d){var e=!g&&(d||c!==j)||((b=c).nodeType?k(a,c,d):l(a,c,d));return b=null,e}];i<f;i++)if(c=d.relative[a[i].type])m=[ta(ua(m),c)];else{if(c=d.filter[a[i].type].apply(null,a[i].matches),c[u]){for(e=++i;e<f;e++)if(d.relative[a[e].type])break;return xa(i>1&&ua(m),i>1&&sa(a.slice(0,i-1).concat({value:" "===a[i-2].type?"*":""})).replace(P,"$1"),c,i<e&&ya(a.slice(i,e)),e<f&&ya(a=a.slice(e)),e<f&&sa(a))}m.push(c)}return ua(m)}function za(a,b){var c=b.length>0,e=a.length>0,f=function(f,g,h,i,k){var l,o,q,r=0,s="0",t=f&&[],u=[],v=j,x=f||e&&d.find.TAG("*",k),y=w+=null==v?1:Math.random()||.1,z=x.length;for(k&&(j=g===n||g||k);s!==z&&null!=(l=x[s]);s++){if(e&&l){o=0,g||l.ownerDocument===n||(m(l),h=!p);while(q=a[o++])if(q(l,g||n,h)){i.push(l);break}k&&(w=y)}c&&((l=!q&&l)&&r--,f&&t.push(l))}if(r+=s,c&&s!==r){o=0;while(q=b[o++])q(t,u,g,h);if(f){if(r>0)while(s--)t[s]||u[s]||(u[s]=E.call(i));u=wa(u)}G.apply(i,u),k&&!f&&u.length>0&&r+b.length>1&&ga.uniqueSort(i)}return k&&(w=y,j=v),t};return c?ia(f):f}return h=ga.compile=function(a,b){var c,d=[],e=[],f=A[a+" "];if(!f){b||(b=g(a)),c=b.length;while(c--)f=ya(b[c]),f[u]?d.push(f):e.push(f);f=A(a,za(e,d)),f.selector=a}return f},i=ga.select=function(a,b,c,e){var f,i,j,k,l,m="function"==typeof a&&a,n=!e&&g(a=m.selector||a);if(c=c||[],1===n.length){if(i=n[0]=n[0].slice(0),i.length>2&&"ID"===(j=i[0]).type&&9===b.nodeType&&p&&d.relative[i[1].type]){if(b=(d.find.ID(j.matches[0].replace(_,aa),b)||[])[0],!b)return c;m&&(b=b.parentNode),a=a.slice(i.shift().value.length)}f=V.needsContext.test(a)?0:i.length;while(f--){if(j=i[f],d.relative[k=j.type])break;if((l=d.find[k])&&(e=l(j.matches[0].replace(_,aa),$.test(i[0].type)&&qa(b.parentNode)||b))){if(i.splice(f,1),a=e.length&&sa(i),!a)return G.apply(c,e),c;break}}}return(m||h(a,n))(e,b,!p,c,!b||$.test(a)&&qa(b.parentNode)||b),c},c.sortStable=u.split("").sort(B).join("")===u,c.detectDuplicates=!!l,m(),c.sortDetached=ja(function(a){return 1&a.compareDocumentPosition(n.createElement("fieldset"))}),ja(function(a){return a.innerHTML="<a href='#'></a>","#"===a.firstChild.getAttribute("href")})||ka("type|href|height|width",function(a,b,c){if(!c)return a.getAttribute(b,"type"===b.toLowerCase()?1:2)}),c.attributes&&ja(function(a){return a.innerHTML="<input/>",a.firstChild.setAttribute("value",""),""===a.firstChild.getAttribute("value")})||ka("value",function(a,b,c){if(!c&&"input"===a.nodeName.toLowerCase())return a.defaultValue}),ja(function(a){return null==a.getAttribute("disabled")})||ka(J,function(a,b,c){var d;if(!c)return a[b]===!0?b.toLowerCase():(d=a.getAttributeNode(b))&&d.specified?d.value:null}),ga}(a);r.find=x,r.expr=x.selectors,r.expr[":"]=r.expr.pseudos,r.uniqueSort=r.unique=x.uniqueSort,r.text=x.getText,r.isXMLDoc=x.isXML,r.contains=x.contains,r.escapeSelector=x.escape;var y=function(a,b,c){var d=[],e=void 0!==c;while((a=a[b])&&9!==a.nodeType)if(1===a.nodeType){if(e&&r(a).is(c))break;d.push(a)}return d},z=function(a,b){for(var c=[];a;a=a.nextSibling)1===a.nodeType&&a!==b&&c.push(a);return c},A=r.expr.match.needsContext;function B(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()}var C=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i,D=/^.[^:#\[\.,]*$/;function E(a,b,c){return r.isFunction(b)?r.grep(a,function(a,d){return!!b.call(a,d,a)!==c}):b.nodeType?r.grep(a,function(a){return a===b!==c}):"string"!=typeof b?r.grep(a,function(a){return i.call(b,a)>-1!==c}):D.test(b)?r.filter(b,a,c):(b=r.filter(b,a),r.grep(a,function(a){return i.call(b,a)>-1!==c&&1===a.nodeType}))}r.filter=function(a,b,c){var d=b[0];return c&&(a=":not("+a+")"),1===b.length&&1===d.nodeType?r.find.matchesSelector(d,a)?[d]:[]:r.find.matches(a,r.grep(b,function(a){return 1===a.nodeType}))},r.fn.extend({find:function(a){var b,c,d=this.length,e=this;if("string"!=typeof a)return this.pushStack(r(a).filter(function(){for(b=0;b<d;b++)if(r.contains(e[b],this))return!0}));for(c=this.pushStack([]),b=0;b<d;b++)r.find(a,e[b],c);return d>1?r.uniqueSort(c):c},filter:function(a){return this.pushStack(E(this,a||[],!1))},not:function(a){return this.pushStack(E(this,a||[],!0))},is:function(a){return!!E(this,"string"==typeof a&&A.test(a)?r(a):a||[],!1).length}});var F,G=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,H=r.fn.init=function(a,b,c){var e,f;if(!a)return this;if(c=c||F,"string"==typeof a){if(e="<"===a[0]&&">"===a[a.length-1]&&a.length>=3?[null,a,null]:G.exec(a),!e||!e[1]&&b)return!b||b.jquery?(b||c).find(a):this.constructor(b).find(a);if(e[1]){if(b=b instanceof r?b[0]:b,r.merge(this,r.parseHTML(e[1],b&&b.nodeType?b.ownerDocument||b:d,!0)),C.test(e[1])&&r.isPlainObject(b))for(e in b)r.isFunction(this[e])?this[e](b[e]):this.attr(e,b[e]);return this}return f=d.getElementById(e[2]),f&&(this[0]=f,this.length=1),this}return a.nodeType?(this[0]=a,this.length=1,this):r.isFunction(a)?void 0!==c.ready?c.ready(a):a(r):r.makeArray(a,this)};H.prototype=r.fn,F=r(d);var I=/^(?:parents|prev(?:Until|All))/,J={children:!0,contents:!0,next:!0,prev:!0};r.fn.extend({has:function(a){var b=r(a,this),c=b.length;return this.filter(function(){for(var a=0;a<c;a++)if(r.contains(this,b[a]))return!0})},closest:function(a,b){var c,d=0,e=this.length,f=[],g="string"!=typeof a&&r(a);if(!A.test(a))for(;d<e;d++)for(c=this[d];c&&c!==b;c=c.parentNode)if(c.nodeType<11&&(g?g.index(c)>-1:1===c.nodeType&&r.find.matchesSelector(c,a))){f.push(c);break}return this.pushStack(f.length>1?r.uniqueSort(f):f)},index:function(a){return a?"string"==typeof a?i.call(r(a),this[0]):i.call(this,a.jquery?a[0]:a):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(a,b){return this.pushStack(r.uniqueSort(r.merge(this.get(),r(a,b))))},addBack:function(a){return this.add(null==a?this.prevObject:this.prevObject.filter(a))}});function K(a,b){while((a=a[b])&&1!==a.nodeType);return a}r.each({parent:function(a){var b=a.parentNode;return b&&11!==b.nodeType?b:null},parents:function(a){return y(a,"parentNode")},parentsUntil:function(a,b,c){return y(a,"parentNode",c)},next:function(a){return K(a,"nextSibling")},prev:function(a){return K(a,"previousSibling")},nextAll:function(a){return y(a,"nextSibling")},prevAll:function(a){return y(a,"previousSibling")},nextUntil:function(a,b,c){return y(a,"nextSibling",c)},prevUntil:function(a,b,c){return y(a,"previousSibling",c)},siblings:function(a){return z((a.parentNode||{}).firstChild,a)},children:function(a){return z(a.firstChild)},contents:function(a){return B(a,"iframe")?a.contentDocument:(B(a,"template")&&(a=a.content||a),r.merge([],a.childNodes))}},function(a,b){r.fn[a]=function(c,d){var e=r.map(this,b,c);return"Until"!==a.slice(-5)&&(d=c),d&&"string"==typeof d&&(e=r.filter(d,e)),this.length>1&&(J[a]||r.uniqueSort(e),I.test(a)&&e.reverse()),this.pushStack(e)}});var L=/[^\x20\t\r\n\f]+/g;function M(a){var b={};return r.each(a.match(L)||[],function(a,c){b[c]=!0}),b}r.Callbacks=function(a){a="string"==typeof a?M(a):r.extend({},a);var b,c,d,e,f=[],g=[],h=-1,i=function(){for(e=e||a.once,d=b=!0;g.length;h=-1){c=g.shift();while(++h<f.length)f[h].apply(c[0],c[1])===!1&&a.stopOnFalse&&(h=f.length,c=!1)}a.memory||(c=!1),b=!1,e&&(f=c?[]:"")},j={add:function(){return f&&(c&&!b&&(h=f.length-1,g.push(c)),function d(b){r.each(b,function(b,c){r.isFunction(c)?a.unique&&j.has(c)||f.push(c):c&&c.length&&"string"!==r.type(c)&&d(c)})}(arguments),c&&!b&&i()),this},remove:function(){return r.each(arguments,function(a,b){var c;while((c=r.inArray(b,f,c))>-1)f.splice(c,1),c<=h&&h--}),this},has:function(a){return a?r.inArray(a,f)>-1:f.length>0},empty:function(){return f&&(f=[]),this},disable:function(){return e=g=[],f=c="",this},disabled:function(){return!f},lock:function(){return e=g=[],c||b||(f=c=""),this},locked:function(){return!!e},fireWith:function(a,c){return e||(c=c||[],c=[a,c.slice?c.slice():c],g.push(c),b||i()),this},fire:function(){return j.fireWith(this,arguments),this},fired:function(){return!!d}};return j};function N(a){return a}function O(a){throw a}function P(a,b,c,d){var e;try{a&&r.isFunction(e=a.promise)?e.call(a).done(b).fail(c):a&&r.isFunction(e=a.then)?e.call(a,b,c):b.apply(void 0,[a].slice(d))}catch(a){c.apply(void 0,[a])}}r.extend({Deferred:function(b){var c=[["notify","progress",r.Callbacks("memory"),r.Callbacks("memory"),2],["resolve","done",r.Callbacks("once memory"),r.Callbacks("once memory"),0,"resolved"],["reject","fail",r.Callbacks("once memory"),r.Callbacks("once memory"),1,"rejected"]],d="pending",e={state:function(){return d},always:function(){return f.done(arguments).fail(arguments),this},"catch":function(a){return e.then(null,a)},pipe:function(){var a=arguments;return r.Deferred(function(b){r.each(c,function(c,d){var e=r.isFunction(a[d[4]])&&a[d[4]];f[d[1]](function(){var a=e&&e.apply(this,arguments);a&&r.isFunction(a.promise)?a.promise().progress(b.notify).done(b.resolve).fail(b.reject):b[d[0]+"With"](this,e?[a]:arguments)})}),a=null}).promise()},then:function(b,d,e){var f=0;function g(b,c,d,e){return function(){var h=this,i=arguments,j=function(){var a,j;if(!(b<f)){if(a=d.apply(h,i),a===c.promise())throw new TypeError("Thenable self-resolution");j=a&&("object"==typeof a||"function"==typeof a)&&a.then,r.isFunction(j)?e?j.call(a,g(f,c,N,e),g(f,c,O,e)):(f++,j.call(a,g(f,c,N,e),g(f,c,O,e),g(f,c,N,c.notifyWith))):(d!==N&&(h=void 0,i=[a]),(e||c.resolveWith)(h,i))}},k=e?j:function(){try{j()}catch(a){r.Deferred.exceptionHook&&r.Deferred.exceptionHook(a,k.stackTrace),b+1>=f&&(d!==O&&(h=void 0,i=[a]),c.rejectWith(h,i))}};b?k():(r.Deferred.getStackHook&&(k.stackTrace=r.Deferred.getStackHook()),a.setTimeout(k))}}return r.Deferred(function(a){c[0][3].add(g(0,a,r.isFunction(e)?e:N,a.notifyWith)),c[1][3].add(g(0,a,r.isFunction(b)?b:N)),c[2][3].add(g(0,a,r.isFunction(d)?d:O))}).promise()},promise:function(a){return null!=a?r.extend(a,e):e}},f={};return r.each(c,function(a,b){var g=b[2],h=b[5];e[b[1]]=g.add,h&&g.add(function(){d=h},c[3-a][2].disable,c[0][2].lock),g.add(b[3].fire),f[b[0]]=function(){return f[b[0]+"With"](this===f?void 0:this,arguments),this},f[b[0]+"With"]=g.fireWith}),e.promise(f),b&&b.call(f,f),f},when:function(a){var b=arguments.length,c=b,d=Array(c),e=f.call(arguments),g=r.Deferred(),h=function(a){return function(c){d[a]=this,e[a]=arguments.length>1?f.call(arguments):c,--b||g.resolveWith(d,e)}};if(b<=1&&(P(a,g.done(h(c)).resolve,g.reject,!b),"pending"===g.state()||r.isFunction(e[c]&&e[c].then)))return g.then();while(c--)P(e[c],h(c),g.reject);return g.promise()}});var Q=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;r.Deferred.exceptionHook=function(b,c){a.console&&a.console.warn&&b&&Q.test(b.name)&&a.console.warn("jQuery.Deferred exception: "+b.message,b.stack,c)},r.readyException=function(b){a.setTimeout(function(){throw b})};var R=r.Deferred();r.fn.ready=function(a){return R.then(a)["catch"](function(a){r.readyException(a)}),this},r.extend({isReady:!1,readyWait:1,ready:function(a){(a===!0?--r.readyWait:r.isReady)||(r.isReady=!0,a!==!0&&--r.readyWait>0||R.resolveWith(d,[r]))}}),r.ready.then=R.then;function S(){d.removeEventListener("DOMContentLoaded",S),
3
+ a.removeEventListener("load",S),r.ready()}"complete"===d.readyState||"loading"!==d.readyState&&!d.documentElement.doScroll?a.setTimeout(r.ready):(d.addEventListener("DOMContentLoaded",S),a.addEventListener("load",S));var T=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===r.type(c)){e=!0;for(h in c)T(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,r.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(r(a),c)})),b))for(;h<i;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},U=function(a){return 1===a.nodeType||9===a.nodeType||!+a.nodeType};function V(){this.expando=r.expando+V.uid++}V.uid=1,V.prototype={cache:function(a){var b=a[this.expando];return b||(b={},U(a)&&(a.nodeType?a[this.expando]=b:Object.defineProperty(a,this.expando,{value:b,configurable:!0}))),b},set:function(a,b,c){var d,e=this.cache(a);if("string"==typeof b)e[r.camelCase(b)]=c;else for(d in b)e[r.camelCase(d)]=b[d];return e},get:function(a,b){return void 0===b?this.cache(a):a[this.expando]&&a[this.expando][r.camelCase(b)]},access:function(a,b,c){return void 0===b||b&&"string"==typeof b&&void 0===c?this.get(a,b):(this.set(a,b,c),void 0!==c?c:b)},remove:function(a,b){var c,d=a[this.expando];if(void 0!==d){if(void 0!==b){Array.isArray(b)?b=b.map(r.camelCase):(b=r.camelCase(b),b=b in d?[b]:b.match(L)||[]),c=b.length;while(c--)delete d[b[c]]}(void 0===b||r.isEmptyObject(d))&&(a.nodeType?a[this.expando]=void 0:delete a[this.expando])}},hasData:function(a){var b=a[this.expando];return void 0!==b&&!r.isEmptyObject(b)}};var W=new V,X=new V,Y=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,Z=/[A-Z]/g;function $(a){return"true"===a||"false"!==a&&("null"===a?null:a===+a+""?+a:Y.test(a)?JSON.parse(a):a)}function _(a,b,c){var d;if(void 0===c&&1===a.nodeType)if(d="data-"+b.replace(Z,"-$&").toLowerCase(),c=a.getAttribute(d),"string"==typeof c){try{c=$(c)}catch(e){}X.set(a,b,c)}else c=void 0;return c}r.extend({hasData:function(a){return X.hasData(a)||W.hasData(a)},data:function(a,b,c){return X.access(a,b,c)},removeData:function(a,b){X.remove(a,b)},_data:function(a,b,c){return W.access(a,b,c)},_removeData:function(a,b){W.remove(a,b)}}),r.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=X.get(f),1===f.nodeType&&!W.get(f,"hasDataAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=r.camelCase(d.slice(5)),_(f,d,e[d])));W.set(f,"hasDataAttrs",!0)}return e}return"object"==typeof a?this.each(function(){X.set(this,a)}):T(this,function(b){var c;if(f&&void 0===b){if(c=X.get(f,a),void 0!==c)return c;if(c=_(f,a),void 0!==c)return c}else this.each(function(){X.set(this,a,b)})},null,b,arguments.length>1,null,!0)},removeData:function(a){return this.each(function(){X.remove(this,a)})}}),r.extend({queue:function(a,b,c){var d;if(a)return b=(b||"fx")+"queue",d=W.get(a,b),c&&(!d||Array.isArray(c)?d=W.access(a,b,r.makeArray(c)):d.push(c)),d||[]},dequeue:function(a,b){b=b||"fx";var c=r.queue(a,b),d=c.length,e=c.shift(),f=r._queueHooks(a,b),g=function(){r.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return W.get(a,c)||W.access(a,c,{empty:r.Callbacks("once memory").add(function(){W.remove(a,[b+"queue",c])})})}}),r.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?r.queue(this[0],a):void 0===b?this:this.each(function(){var c=r.queue(this,a,b);r._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&r.dequeue(this,a)})},dequeue:function(a){return this.each(function(){r.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=r.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=W.get(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}});var aa=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,ba=new RegExp("^(?:([+-])=|)("+aa+")([a-z%]*)$","i"),ca=["Top","Right","Bottom","Left"],da=function(a,b){return a=b||a,"none"===a.style.display||""===a.style.display&&r.contains(a.ownerDocument,a)&&"none"===r.css(a,"display")},ea=function(a,b,c,d){var e,f,g={};for(f in b)g[f]=a.style[f],a.style[f]=b[f];e=c.apply(a,d||[]);for(f in b)a.style[f]=g[f];return e};function fa(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return r.css(a,b,"")},i=h(),j=c&&c[3]||(r.cssNumber[b]?"":"px"),k=(r.cssNumber[b]||"px"!==j&&+i)&&ba.exec(r.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,r.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var ga={};function ha(a){var b,c=a.ownerDocument,d=a.nodeName,e=ga[d];return e?e:(b=c.body.appendChild(c.createElement(d)),e=r.css(b,"display"),b.parentNode.removeChild(b),"none"===e&&(e="block"),ga[d]=e,e)}function ia(a,b){for(var c,d,e=[],f=0,g=a.length;f<g;f++)d=a[f],d.style&&(c=d.style.display,b?("none"===c&&(e[f]=W.get(d,"display")||null,e[f]||(d.style.display="")),""===d.style.display&&da(d)&&(e[f]=ha(d))):"none"!==c&&(e[f]="none",W.set(d,"display",c)));for(f=0;f<g;f++)null!=e[f]&&(a[f].style.display=e[f]);return a}r.fn.extend({show:function(){return ia(this,!0)},hide:function(){return ia(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){da(this)?r(this).show():r(this).hide()})}});var ja=/^(?:checkbox|radio)$/i,ka=/<([a-z][^\/\0>\x20\t\r\n\f]+)/i,la=/^$|\/(?:java|ecma)script/i,ma={option:[1,"<select multiple='multiple'>","</select>"],thead:[1,"<table>","</table>"],col:[2,"<table><colgroup>","</colgroup></table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],_default:[0,"",""]};ma.optgroup=ma.option,ma.tbody=ma.tfoot=ma.colgroup=ma.caption=ma.thead,ma.th=ma.td;function na(a,b){var c;return c="undefined"!=typeof a.getElementsByTagName?a.getElementsByTagName(b||"*"):"undefined"!=typeof a.querySelectorAll?a.querySelectorAll(b||"*"):[],void 0===b||b&&B(a,b)?r.merge([a],c):c}function oa(a,b){for(var c=0,d=a.length;c<d;c++)W.set(a[c],"globalEval",!b||W.get(b[c],"globalEval"))}var pa=/<|&#?\w+;/;function qa(a,b,c,d,e){for(var f,g,h,i,j,k,l=b.createDocumentFragment(),m=[],n=0,o=a.length;n<o;n++)if(f=a[n],f||0===f)if("object"===r.type(f))r.merge(m,f.nodeType?[f]:f);else if(pa.test(f)){g=g||l.appendChild(b.createElement("div")),h=(ka.exec(f)||["",""])[1].toLowerCase(),i=ma[h]||ma._default,g.innerHTML=i[1]+r.htmlPrefilter(f)+i[2],k=i[0];while(k--)g=g.lastChild;r.merge(m,g.childNodes),g=l.firstChild,g.textContent=""}else m.push(b.createTextNode(f));l.textContent="",n=0;while(f=m[n++])if(d&&r.inArray(f,d)>-1)e&&e.push(f);else if(j=r.contains(f.ownerDocument,f),g=na(l.appendChild(f),"script"),j&&oa(g),c){k=0;while(f=g[k++])la.test(f.type||"")&&c.push(f)}return l}!function(){var a=d.createDocumentFragment(),b=a.appendChild(d.createElement("div")),c=d.createElement("input");c.setAttribute("type","radio"),c.setAttribute("checked","checked"),c.setAttribute("name","t"),b.appendChild(c),o.checkClone=b.cloneNode(!0).cloneNode(!0).lastChild.checked,b.innerHTML="<textarea>x</textarea>",o.noCloneChecked=!!b.cloneNode(!0).lastChild.defaultValue}();var ra=d.documentElement,sa=/^key/,ta=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,ua=/^([^.]*)(?:\.(.+)|)/;function va(){return!0}function wa(){return!1}function xa(){try{return d.activeElement}catch(a){}}function ya(a,b,c,d,e,f){var g,h;if("object"==typeof b){"string"!=typeof c&&(d=d||c,c=void 0);for(h in b)ya(a,h,c,d,b[h],f);return a}if(null==d&&null==e?(e=c,d=c=void 0):null==e&&("string"==typeof c?(e=d,d=void 0):(e=d,d=c,c=void 0)),e===!1)e=wa;else if(!e)return a;return 1===f&&(g=e,e=function(a){return r().off(a),g.apply(this,arguments)},e.guid=g.guid||(g.guid=r.guid++)),a.each(function(){r.event.add(this,b,e,d,c)})}r.event={global:{},add:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.get(a);if(q){c.handler&&(f=c,c=f.handler,e=f.selector),e&&r.find.matchesSelector(ra,e),c.guid||(c.guid=r.guid++),(i=q.events)||(i=q.events={}),(g=q.handle)||(g=q.handle=function(b){return"undefined"!=typeof r&&r.event.triggered!==b.type?r.event.dispatch.apply(a,arguments):void 0}),b=(b||"").match(L)||[""],j=b.length;while(j--)h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n&&(l=r.event.special[n]||{},n=(e?l.delegateType:l.bindType)||n,l=r.event.special[n]||{},k=r.extend({type:n,origType:p,data:d,handler:c,guid:c.guid,selector:e,needsContext:e&&r.expr.match.needsContext.test(e),namespace:o.join(".")},f),(m=i[n])||(m=i[n]=[],m.delegateCount=0,l.setup&&l.setup.call(a,d,o,g)!==!1||a.addEventListener&&a.addEventListener(n,g)),l.add&&(l.add.call(a,k),k.handler.guid||(k.handler.guid=c.guid)),e?m.splice(m.delegateCount++,0,k):m.push(k),r.event.global[n]=!0)}},remove:function(a,b,c,d,e){var f,g,h,i,j,k,l,m,n,o,p,q=W.hasData(a)&&W.get(a);if(q&&(i=q.events)){b=(b||"").match(L)||[""],j=b.length;while(j--)if(h=ua.exec(b[j])||[],n=p=h[1],o=(h[2]||"").split(".").sort(),n){l=r.event.special[n]||{},n=(d?l.delegateType:l.bindType)||n,m=i[n]||[],h=h[2]&&new RegExp("(^|\\.)"+o.join("\\.(?:.*\\.|)")+"(\\.|$)"),g=f=m.length;while(f--)k=m[f],!e&&p!==k.origType||c&&c.guid!==k.guid||h&&!h.test(k.namespace)||d&&d!==k.selector&&("**"!==d||!k.selector)||(m.splice(f,1),k.selector&&m.delegateCount--,l.remove&&l.remove.call(a,k));g&&!m.length&&(l.teardown&&l.teardown.call(a,o,q.handle)!==!1||r.removeEvent(a,n,q.handle),delete i[n])}else for(n in i)r.event.remove(a,n+b[j],c,d,!0);r.isEmptyObject(i)&&W.remove(a,"handle events")}},dispatch:function(a){var b=r.event.fix(a),c,d,e,f,g,h,i=new Array(arguments.length),j=(W.get(this,"events")||{})[b.type]||[],k=r.event.special[b.type]||{};for(i[0]=b,c=1;c<arguments.length;c++)i[c]=arguments[c];if(b.delegateTarget=this,!k.preDispatch||k.preDispatch.call(this,b)!==!1){h=r.event.handlers.call(this,b,j),c=0;while((f=h[c++])&&!b.isPropagationStopped()){b.currentTarget=f.elem,d=0;while((g=f.handlers[d++])&&!b.isImmediatePropagationStopped())b.rnamespace&&!b.rnamespace.test(g.namespace)||(b.handleObj=g,b.data=g.data,e=((r.event.special[g.origType]||{}).handle||g.handler).apply(f.elem,i),void 0!==e&&(b.result=e)===!1&&(b.preventDefault(),b.stopPropagation()))}return k.postDispatch&&k.postDispatch.call(this,b),b.result}},handlers:function(a,b){var c,d,e,f,g,h=[],i=b.delegateCount,j=a.target;if(i&&j.nodeType&&!("click"===a.type&&a.button>=1))for(;j!==this;j=j.parentNode||this)if(1===j.nodeType&&("click"!==a.type||j.disabled!==!0)){for(f=[],g={},c=0;c<i;c++)d=b[c],e=d.selector+" ",void 0===g[e]&&(g[e]=d.needsContext?r(e,this).index(j)>-1:r.find(e,this,null,[j]).length),g[e]&&f.push(d);f.length&&h.push({elem:j,handlers:f})}return j=this,i<b.length&&h.push({elem:j,handlers:b.slice(i)}),h},addProp:function(a,b){Object.defineProperty(r.Event.prototype,a,{enumerable:!0,configurable:!0,get:r.isFunction(b)?function(){if(this.originalEvent)return b(this.originalEvent)}:function(){if(this.originalEvent)return this.originalEvent[a]},set:function(b){Object.defineProperty(this,a,{enumerable:!0,configurable:!0,writable:!0,value:b})}})},fix:function(a){return a[r.expando]?a:new r.Event(a)},special:{load:{noBubble:!0},focus:{trigger:function(){if(this!==xa()&&this.focus)return this.focus(),!1},delegateType:"focusin"},blur:{trigger:function(){if(this===xa()&&this.blur)return this.blur(),!1},delegateType:"focusout"},click:{trigger:function(){if("checkbox"===this.type&&this.click&&B(this,"input"))return this.click(),!1},_default:function(a){return B(a.target,"a")}},beforeunload:{postDispatch:function(a){void 0!==a.result&&a.originalEvent&&(a.originalEvent.returnValue=a.result)}}}},r.removeEvent=function(a,b,c){a.removeEventListener&&a.removeEventListener(b,c)},r.Event=function(a,b){return this instanceof r.Event?(a&&a.type?(this.originalEvent=a,this.type=a.type,this.isDefaultPrevented=a.defaultPrevented||void 0===a.defaultPrevented&&a.returnValue===!1?va:wa,this.target=a.target&&3===a.target.nodeType?a.target.parentNode:a.target,this.currentTarget=a.currentTarget,this.relatedTarget=a.relatedTarget):this.type=a,b&&r.extend(this,b),this.timeStamp=a&&a.timeStamp||r.now(),void(this[r.expando]=!0)):new r.Event(a,b)},r.Event.prototype={constructor:r.Event,isDefaultPrevented:wa,isPropagationStopped:wa,isImmediatePropagationStopped:wa,isSimulated:!1,preventDefault:function(){var a=this.originalEvent;this.isDefaultPrevented=va,a&&!this.isSimulated&&a.preventDefault()},stopPropagation:function(){var a=this.originalEvent;this.isPropagationStopped=va,a&&!this.isSimulated&&a.stopPropagation()},stopImmediatePropagation:function(){var a=this.originalEvent;this.isImmediatePropagationStopped=va,a&&!this.isSimulated&&a.stopImmediatePropagation(),this.stopPropagation()}},r.each({altKey:!0,bubbles:!0,cancelable:!0,changedTouches:!0,ctrlKey:!0,detail:!0,eventPhase:!0,metaKey:!0,pageX:!0,pageY:!0,shiftKey:!0,view:!0,"char":!0,charCode:!0,key:!0,keyCode:!0,button:!0,buttons:!0,clientX:!0,clientY:!0,offsetX:!0,offsetY:!0,pointerId:!0,pointerType:!0,screenX:!0,screenY:!0,targetTouches:!0,toElement:!0,touches:!0,which:function(a){var b=a.button;return null==a.which&&sa.test(a.type)?null!=a.charCode?a.charCode:a.keyCode:!a.which&&void 0!==b&&ta.test(a.type)?1&b?1:2&b?3:4&b?2:0:a.which}},r.event.addProp),r.each({mouseenter:"mouseover",mouseleave:"mouseout",pointerenter:"pointerover",pointerleave:"pointerout"},function(a,b){r.event.special[a]={delegateType:b,bindType:b,handle:function(a){var c,d=this,e=a.relatedTarget,f=a.handleObj;return e&&(e===d||r.contains(d,e))||(a.type=f.origType,c=f.handler.apply(this,arguments),a.type=b),c}}}),r.fn.extend({on:function(a,b,c,d){return ya(this,a,b,c,d)},one:function(a,b,c,d){return ya(this,a,b,c,d,1)},off:function(a,b,c){var d,e;if(a&&a.preventDefault&&a.handleObj)return d=a.handleObj,r(a.delegateTarget).off(d.namespace?d.origType+"."+d.namespace:d.origType,d.selector,d.handler),this;if("object"==typeof a){for(e in a)this.off(e,b,a[e]);return this}return b!==!1&&"function"!=typeof b||(c=b,b=void 0),c===!1&&(c=wa),this.each(function(){r.event.remove(this,a,c,b)})}});var za=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,Aa=/<script|<style|<link/i,Ba=/checked\s*(?:[^=]|=\s*.checked.)/i,Ca=/^true\/(.*)/,Da=/^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;function Ea(a,b){return B(a,"table")&&B(11!==b.nodeType?b:b.firstChild,"tr")?r(">tbody",a)[0]||a:a}function Fa(a){return a.type=(null!==a.getAttribute("type"))+"/"+a.type,a}function Ga(a){var b=Ca.exec(a.type);return b?a.type=b[1]:a.removeAttribute("type"),a}function Ha(a,b){var c,d,e,f,g,h,i,j;if(1===b.nodeType){if(W.hasData(a)&&(f=W.access(a),g=W.set(b,f),j=f.events)){delete g.handle,g.events={};for(e in j)for(c=0,d=j[e].length;c<d;c++)r.event.add(b,e,j[e][c])}X.hasData(a)&&(h=X.access(a),i=r.extend({},h),X.set(b,i))}}function Ia(a,b){var c=b.nodeName.toLowerCase();"input"===c&&ja.test(a.type)?b.checked=a.checked:"input"!==c&&"textarea"!==c||(b.defaultValue=a.defaultValue)}function Ja(a,b,c,d){b=g.apply([],b);var e,f,h,i,j,k,l=0,m=a.length,n=m-1,q=b[0],s=r.isFunction(q);if(s||m>1&&"string"==typeof q&&!o.checkClone&&Ba.test(q))return a.each(function(e){var f=a.eq(e);s&&(b[0]=q.call(this,e,f.html())),Ja(f,b,c,d)});if(m&&(e=qa(b,a[0].ownerDocument,!1,a,d),f=e.firstChild,1===e.childNodes.length&&(e=f),f||d)){for(h=r.map(na(e,"script"),Fa),i=h.length;l<m;l++)j=e,l!==n&&(j=r.clone(j,!0,!0),i&&r.merge(h,na(j,"script"))),c.call(a[l],j,l);if(i)for(k=h[h.length-1].ownerDocument,r.map(h,Ga),l=0;l<i;l++)j=h[l],la.test(j.type||"")&&!W.access(j,"globalEval")&&r.contains(k,j)&&(j.src?r._evalUrl&&r._evalUrl(j.src):p(j.textContent.replace(Da,""),k))}return a}function Ka(a,b,c){for(var d,e=b?r.filter(b,a):a,f=0;null!=(d=e[f]);f++)c||1!==d.nodeType||r.cleanData(na(d)),d.parentNode&&(c&&r.contains(d.ownerDocument,d)&&oa(na(d,"script")),d.parentNode.removeChild(d));return a}r.extend({htmlPrefilter:function(a){return a.replace(za,"<$1></$2>")},clone:function(a,b,c){var d,e,f,g,h=a.cloneNode(!0),i=r.contains(a.ownerDocument,a);if(!(o.noCloneChecked||1!==a.nodeType&&11!==a.nodeType||r.isXMLDoc(a)))for(g=na(h),f=na(a),d=0,e=f.length;d<e;d++)Ia(f[d],g[d]);if(b)if(c)for(f=f||na(a),g=g||na(h),d=0,e=f.length;d<e;d++)Ha(f[d],g[d]);else Ha(a,h);return g=na(h,"script"),g.length>0&&oa(g,!i&&na(a,"script")),h},cleanData:function(a){for(var b,c,d,e=r.event.special,f=0;void 0!==(c=a[f]);f++)if(U(c)){if(b=c[W.expando]){if(b.events)for(d in b.events)e[d]?r.event.remove(c,d):r.removeEvent(c,d,b.handle);c[W.expando]=void 0}c[X.expando]&&(c[X.expando]=void 0)}}}),r.fn.extend({detach:function(a){return Ka(this,a,!0)},remove:function(a){return Ka(this,a)},text:function(a){return T(this,function(a){return void 0===a?r.text(this):this.empty().each(function(){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||(this.textContent=a)})},null,a,arguments.length)},append:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.appendChild(a)}})},prepend:function(){return Ja(this,arguments,function(a){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var b=Ea(this,a);b.insertBefore(a,b.firstChild)}})},before:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this)})},after:function(){return Ja(this,arguments,function(a){this.parentNode&&this.parentNode.insertBefore(a,this.nextSibling)})},empty:function(){for(var a,b=0;null!=(a=this[b]);b++)1===a.nodeType&&(r.cleanData(na(a,!1)),a.textContent="");return this},clone:function(a,b){return a=null!=a&&a,b=null==b?a:b,this.map(function(){return r.clone(this,a,b)})},html:function(a){return T(this,function(a){var b=this[0]||{},c=0,d=this.length;if(void 0===a&&1===b.nodeType)return b.innerHTML;if("string"==typeof a&&!Aa.test(a)&&!ma[(ka.exec(a)||["",""])[1].toLowerCase()]){a=r.htmlPrefilter(a);try{for(;c<d;c++)b=this[c]||{},1===b.nodeType&&(r.cleanData(na(b,!1)),b.innerHTML=a);b=0}catch(e){}}b&&this.empty().append(a)},null,a,arguments.length)},replaceWith:function(){var a=[];return Ja(this,arguments,function(b){var c=this.parentNode;r.inArray(this,a)<0&&(r.cleanData(na(this)),c&&c.replaceChild(b,this))},a)}}),r.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){r.fn[a]=function(a){for(var c,d=[],e=r(a),f=e.length-1,g=0;g<=f;g++)c=g===f?this:this.clone(!0),r(e[g])[b](c),h.apply(d,c.get());return this.pushStack(d)}});var La=/^margin/,Ma=new RegExp("^("+aa+")(?!px)[a-z%]+$","i"),Na=function(b){var c=b.ownerDocument.defaultView;return c&&c.opener||(c=a),c.getComputedStyle(b)};!function(){function b(){if(i){i.style.cssText="box-sizing:border-box;position:relative;display:block;margin:auto;border:1px;padding:1px;top:1%;width:50%",i.innerHTML="",ra.appendChild(h);var b=a.getComputedStyle(i);c="1%"!==b.top,g="2px"===b.marginLeft,e="4px"===b.width,i.style.marginRight="50%",f="4px"===b.marginRight,ra.removeChild(h),i=null}}var c,e,f,g,h=d.createElement("div"),i=d.createElement("div");i.style&&(i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",o.clearCloneStyle="content-box"===i.style.backgroundClip,h.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",h.appendChild(i),r.extend(o,{pixelPosition:function(){return b(),c},boxSizingReliable:function(){return b(),e},pixelMarginRight:function(){return b(),f},reliableMarginLeft:function(){return b(),g}}))}();function Oa(a,b,c){var d,e,f,g,h=a.style;return c=c||Na(a),c&&(g=c.getPropertyValue(b)||c[b],""!==g||r.contains(a.ownerDocument,a)||(g=r.style(a,b)),!o.pixelMarginRight()&&Ma.test(g)&&La.test(b)&&(d=h.width,e=h.minWidth,f=h.maxWidth,h.minWidth=h.maxWidth=h.width=g,g=c.width,h.width=d,h.minWidth=e,h.maxWidth=f)),void 0!==g?g+"":g}function Pa(a,b){return{get:function(){return a()?void delete this.get:(this.get=b).apply(this,arguments)}}}var Qa=/^(none|table(?!-c[ea]).+)/,Ra=/^--/,Sa={position:"absolute",visibility:"hidden",display:"block"},Ta={letterSpacing:"0",fontWeight:"400"},Ua=["Webkit","Moz","ms"],Va=d.createElement("div").style;function Wa(a){if(a in Va)return a;var b=a[0].toUpperCase()+a.slice(1),c=Ua.length;while(c--)if(a=Ua[c]+b,a in Va)return a}function Xa(a){var b=r.cssProps[a];return b||(b=r.cssProps[a]=Wa(a)||a),b}function Ya(a,b,c){var d=ba.exec(b);return d?Math.max(0,d[2]-(c||0))+(d[3]||"px"):b}function Za(a,b,c,d,e){var f,g=0;for(f=c===(d?"border":"content")?4:"width"===b?1:0;f<4;f+=2)"margin"===c&&(g+=r.css(a,c+ca[f],!0,e)),d?("content"===c&&(g-=r.css(a,"padding"+ca[f],!0,e)),"margin"!==c&&(g-=r.css(a,"border"+ca[f]+"Width",!0,e))):(g+=r.css(a,"padding"+ca[f],!0,e),"padding"!==c&&(g+=r.css(a,"border"+ca[f]+"Width",!0,e)));return g}function $a(a,b,c){var d,e=Na(a),f=Oa(a,b,e),g="border-box"===r.css(a,"boxSizing",!1,e);return Ma.test(f)?f:(d=g&&(o.boxSizingReliable()||f===a.style[b]),"auto"===f&&(f=a["offset"+b[0].toUpperCase()+b.slice(1)]),f=parseFloat(f)||0,f+Za(a,b,c||(g?"border":"content"),d,e)+"px")}r.extend({cssHooks:{opacity:{get:function(a,b){if(b){var c=Oa(a,"opacity");return""===c?"1":c}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(a,b,c,d){if(a&&3!==a.nodeType&&8!==a.nodeType&&a.style){var e,f,g,h=r.camelCase(b),i=Ra.test(b),j=a.style;return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],void 0===c?g&&"get"in g&&void 0!==(e=g.get(a,!1,d))?e:j[b]:(f=typeof c,"string"===f&&(e=ba.exec(c))&&e[1]&&(c=fa(a,b,e),f="number"),null!=c&&c===c&&("number"===f&&(c+=e&&e[3]||(r.cssNumber[h]?"":"px")),o.clearCloneStyle||""!==c||0!==b.indexOf("background")||(j[b]="inherit"),g&&"set"in g&&void 0===(c=g.set(a,c,d))||(i?j.setProperty(b,c):j[b]=c)),void 0)}},css:function(a,b,c,d){var e,f,g,h=r.camelCase(b),i=Ra.test(b);return i||(b=Xa(h)),g=r.cssHooks[b]||r.cssHooks[h],g&&"get"in g&&(e=g.get(a,!0,c)),void 0===e&&(e=Oa(a,b,d)),"normal"===e&&b in Ta&&(e=Ta[b]),""===c||c?(f=parseFloat(e),c===!0||isFinite(f)?f||0:e):e}}),r.each(["height","width"],function(a,b){r.cssHooks[b]={get:function(a,c,d){if(c)return!Qa.test(r.css(a,"display"))||a.getClientRects().length&&a.getBoundingClientRect().width?$a(a,b,d):ea(a,Sa,function(){return $a(a,b,d)})},set:function(a,c,d){var e,f=d&&Na(a),g=d&&Za(a,b,d,"border-box"===r.css(a,"boxSizing",!1,f),f);return g&&(e=ba.exec(c))&&"px"!==(e[3]||"px")&&(a.style[b]=c,c=r.css(a,b)),Ya(a,c,g)}}}),r.cssHooks.marginLeft=Pa(o.reliableMarginLeft,function(a,b){if(b)return(parseFloat(Oa(a,"marginLeft"))||a.getBoundingClientRect().left-ea(a,{marginLeft:0},function(){return a.getBoundingClientRect().left}))+"px"}),r.each({margin:"",padding:"",border:"Width"},function(a,b){r.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];d<4;d++)e[a+ca[d]+b]=f[d]||f[d-2]||f[0];return e}},La.test(a)||(r.cssHooks[a+b].set=Ya)}),r.fn.extend({css:function(a,b){return T(this,function(a,b,c){var d,e,f={},g=0;if(Array.isArray(b)){for(d=Na(a),e=b.length;g<e;g++)f[b[g]]=r.css(a,b[g],!1,d);return f}return void 0!==c?r.style(a,b,c):r.css(a,b)},a,b,arguments.length>1)}});function _a(a,b,c,d,e){return new _a.prototype.init(a,b,c,d,e)}r.Tween=_a,_a.prototype={constructor:_a,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||r.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(r.cssNumber[c]?"":"px")},cur:function(){var a=_a.propHooks[this.prop];return a&&a.get?a.get(this):_a.propHooks._default.get(this)},run:function(a){var b,c=_a.propHooks[this.prop];return this.options.duration?this.pos=b=r.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):_a.propHooks._default.set(this),this}},_a.prototype.init.prototype=_a.prototype,_a.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=r.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){r.fx.step[a.prop]?r.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[r.cssProps[a.prop]]&&!r.cssHooks[a.prop]?a.elem[a.prop]=a.now:r.style(a.elem,a.prop,a.now+a.unit)}}},_a.propHooks.scrollTop=_a.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},r.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},r.fx=_a.prototype.init,r.fx.step={};var ab,bb,cb=/^(?:toggle|show|hide)$/,db=/queueHooks$/;function eb(){bb&&(d.hidden===!1&&a.requestAnimationFrame?a.requestAnimationFrame(eb):a.setTimeout(eb,r.fx.interval),r.fx.tick())}function fb(){return a.setTimeout(function(){ab=void 0}),ab=r.now()}function gb(a,b){var c,d=0,e={height:a};for(b=b?1:0;d<4;d+=2-b)c=ca[d],e["margin"+c]=e["padding"+c]=a;return b&&(e.opacity=e.width=a),e}function hb(a,b,c){for(var d,e=(kb.tweeners[b]||[]).concat(kb.tweeners["*"]),f=0,g=e.length;f<g;f++)if(d=e[f].call(c,b,a))return d}function ib(a,b,c){var d,e,f,g,h,i,j,k,l="width"in b||"height"in b,m=this,n={},o=a.style,p=a.nodeType&&da(a),q=W.get(a,"fxshow");c.queue||(g=r._queueHooks(a,"fx"),null==g.unqueued&&(g.unqueued=0,h=g.empty.fire,g.empty.fire=function(){g.unqueued||h()}),g.unqueued++,m.always(function(){m.always(function(){g.unqueued--,r.queue(a,"fx").length||g.empty.fire()})}));for(d in b)if(e=b[d],cb.test(e)){if(delete b[d],f=f||"toggle"===e,e===(p?"hide":"show")){if("show"!==e||!q||void 0===q[d])continue;p=!0}n[d]=q&&q[d]||r.style(a,d)}if(i=!r.isEmptyObject(b),i||!r.isEmptyObject(n)){l&&1===a.nodeType&&(c.overflow=[o.overflow,o.overflowX,o.overflowY],j=q&&q.display,null==j&&(j=W.get(a,"display")),k=r.css(a,"display"),"none"===k&&(j?k=j:(ia([a],!0),j=a.style.display||j,k=r.css(a,"display"),ia([a]))),("inline"===k||"inline-block"===k&&null!=j)&&"none"===r.css(a,"float")&&(i||(m.done(function(){o.display=j}),null==j&&(k=o.display,j="none"===k?"":k)),o.display="inline-block")),c.overflow&&(o.overflow="hidden",m.always(function(){o.overflow=c.overflow[0],o.overflowX=c.overflow[1],o.overflowY=c.overflow[2]})),i=!1;for(d in n)i||(q?"hidden"in q&&(p=q.hidden):q=W.access(a,"fxshow",{display:j}),f&&(q.hidden=!p),p&&ia([a],!0),m.done(function(){p||ia([a]),W.remove(a,"fxshow");for(d in n)r.style(a,d,n[d])})),i=hb(p?q[d]:0,d,m),d in q||(q[d]=i.start,p&&(i.end=i.start,i.start=0))}}function jb(a,b){var c,d,e,f,g;for(c in a)if(d=r.camelCase(c),e=b[d],f=a[c],Array.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=r.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function kb(a,b,c){var d,e,f=0,g=kb.prefilters.length,h=r.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=ab||fb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;g<i;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),f<1&&i?c:(i||h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:r.extend({},b),opts:r.extend(!0,{specialEasing:{},easing:r.easing._default},c),originalProperties:b,originalOptions:c,startTime:ab||fb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=r.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;c<d;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]),this}}),k=j.props;for(jb(k,j.opts.specialEasing);f<g;f++)if(d=kb.prefilters[f].call(j,a,k,j.opts))return r.isFunction(d.stop)&&(r._queueHooks(j.elem,j.opts.queue).stop=r.proxy(d.stop,d)),d;return r.map(k,hb,j),r.isFunction(j.opts.start)&&j.opts.start.call(a,j),j.progress(j.opts.progress).done(j.opts.done,j.opts.complete).fail(j.opts.fail).always(j.opts.always),r.fx.timer(r.extend(i,{elem:a,anim:j,queue:j.opts.queue})),j}r.Animation=r.extend(kb,{tweeners:{"*":[function(a,b){var c=this.createTween(a,b);return fa(c.elem,a,ba.exec(b),c),c}]},tweener:function(a,b){r.isFunction(a)?(b=a,a=["*"]):a=a.match(L);for(var c,d=0,e=a.length;d<e;d++)c=a[d],kb.tweeners[c]=kb.tweeners[c]||[],kb.tweeners[c].unshift(b)},prefilters:[ib],prefilter:function(a,b){b?kb.prefilters.unshift(a):kb.prefilters.push(a)}}),r.speed=function(a,b,c){var d=a&&"object"==typeof a?r.extend({},a):{complete:c||!c&&b||r.isFunction(a)&&a,duration:a,easing:c&&b||b&&!r.isFunction(b)&&b};return r.fx.off?d.duration=0:"number"!=typeof d.duration&&(d.duration in r.fx.speeds?d.duration=r.fx.speeds[d.duration]:d.duration=r.fx.speeds._default),null!=d.queue&&d.queue!==!0||(d.queue="fx"),d.old=d.complete,d.complete=function(){r.isFunction(d.old)&&d.old.call(this),d.queue&&r.dequeue(this,d.queue)},d},r.fn.extend({fadeTo:function(a,b,c,d){return this.filter(da).css("opacity",0).show().end().animate({opacity:b},a,c,d)},animate:function(a,b,c,d){var e=r.isEmptyObject(a),f=r.speed(b,c,d),g=function(){var b=kb(this,r.extend({},a),f);(e||W.get(this,"finish"))&&b.stop(!0)};return g.finish=g,e||f.queue===!1?this.each(g):this.queue(f.queue,g)},stop:function(a,b,c){var d=function(a){var b=a.stop;delete a.stop,b(c)};return"string"!=typeof a&&(c=b,b=a,a=void 0),b&&a!==!1&&this.queue(a||"fx",[]),this.each(function(){var b=!0,e=null!=a&&a+"queueHooks",f=r.timers,g=W.get(this);if(e)g[e]&&g[e].stop&&d(g[e]);else for(e in g)g[e]&&g[e].stop&&db.test(e)&&d(g[e]);for(e=f.length;e--;)f[e].elem!==this||null!=a&&f[e].queue!==a||(f[e].anim.stop(c),b=!1,f.splice(e,1));!b&&c||r.dequeue(this,a)})},finish:function(a){return a!==!1&&(a=a||"fx"),this.each(function(){var b,c=W.get(this),d=c[a+"queue"],e=c[a+"queueHooks"],f=r.timers,g=d?d.length:0;for(c.finish=!0,r.queue(this,a,[]),e&&e.stop&&e.stop.call(this,!0),b=f.length;b--;)f[b].elem===this&&f[b].queue===a&&(f[b].anim.stop(!0),f.splice(b,1));for(b=0;b<g;b++)d[b]&&d[b].finish&&d[b].finish.call(this);delete c.finish})}}),r.each(["toggle","show","hide"],function(a,b){var c=r.fn[b];r.fn[b]=function(a,d,e){return null==a||"boolean"==typeof a?c.apply(this,arguments):this.animate(gb(b,!0),a,d,e)}}),r.each({slideDown:gb("show"),slideUp:gb("hide"),slideToggle:gb("toggle"),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){r.fn[a]=function(a,c,d){return this.animate(b,a,c,d)}}),r.timers=[],r.fx.tick=function(){var a,b=0,c=r.timers;for(ab=r.now();b<c.length;b++)a=c[b],a()||c[b]!==a||c.splice(b--,1);c.length||r.fx.stop(),ab=void 0},r.fx.timer=function(a){r.timers.push(a),r.fx.start()},r.fx.interval=13,r.fx.start=function(){bb||(bb=!0,eb())},r.fx.stop=function(){bb=null},r.fx.speeds={slow:600,fast:200,_default:400},r.fn.delay=function(b,c){return b=r.fx?r.fx.speeds[b]||b:b,c=c||"fx",this.queue(c,function(c,d){var e=a.setTimeout(c,b);d.stop=function(){a.clearTimeout(e)}})},function(){var a=d.createElement("input"),b=d.createElement("select"),c=b.appendChild(d.createElement("option"));a.type="checkbox",o.checkOn=""!==a.value,o.optSelected=c.selected,a=d.createElement("input"),a.value="t",a.type="radio",o.radioValue="t"===a.value}();var lb,mb=r.expr.attrHandle;r.fn.extend({attr:function(a,b){return T(this,r.attr,a,b,arguments.length>1)},removeAttr:function(a){return this.each(function(){r.removeAttr(this,a)})}}),r.extend({attr:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return"undefined"==typeof a.getAttribute?r.prop(a,b,c):(1===f&&r.isXMLDoc(a)||(e=r.attrHooks[b.toLowerCase()]||(r.expr.match.bool.test(b)?lb:void 0)),void 0!==c?null===c?void r.removeAttr(a,b):e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:(a.setAttribute(b,c+""),c):e&&"get"in e&&null!==(d=e.get(a,b))?d:(d=r.find.attr(a,b),
4
+ null==d?void 0:d))},attrHooks:{type:{set:function(a,b){if(!o.radioValue&&"radio"===b&&B(a,"input")){var c=a.value;return a.setAttribute("type",b),c&&(a.value=c),b}}}},removeAttr:function(a,b){var c,d=0,e=b&&b.match(L);if(e&&1===a.nodeType)while(c=e[d++])a.removeAttribute(c)}}),lb={set:function(a,b,c){return b===!1?r.removeAttr(a,c):a.setAttribute(c,c),c}},r.each(r.expr.match.bool.source.match(/\w+/g),function(a,b){var c=mb[b]||r.find.attr;mb[b]=function(a,b,d){var e,f,g=b.toLowerCase();return d||(f=mb[g],mb[g]=e,e=null!=c(a,b,d)?g:null,mb[g]=f),e}});var nb=/^(?:input|select|textarea|button)$/i,ob=/^(?:a|area)$/i;r.fn.extend({prop:function(a,b){return T(this,r.prop,a,b,arguments.length>1)},removeProp:function(a){return this.each(function(){delete this[r.propFix[a]||a]})}}),r.extend({prop:function(a,b,c){var d,e,f=a.nodeType;if(3!==f&&8!==f&&2!==f)return 1===f&&r.isXMLDoc(a)||(b=r.propFix[b]||b,e=r.propHooks[b]),void 0!==c?e&&"set"in e&&void 0!==(d=e.set(a,c,b))?d:a[b]=c:e&&"get"in e&&null!==(d=e.get(a,b))?d:a[b]},propHooks:{tabIndex:{get:function(a){var b=r.find.attr(a,"tabindex");return b?parseInt(b,10):nb.test(a.nodeName)||ob.test(a.nodeName)&&a.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),o.optSelected||(r.propHooks.selected={get:function(a){var b=a.parentNode;return b&&b.parentNode&&b.parentNode.selectedIndex,null},set:function(a){var b=a.parentNode;b&&(b.selectedIndex,b.parentNode&&b.parentNode.selectedIndex)}}),r.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){r.propFix[this.toLowerCase()]=this});function pb(a){var b=a.match(L)||[];return b.join(" ")}function qb(a){return a.getAttribute&&a.getAttribute("class")||""}r.fn.extend({addClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).addClass(a.call(this,b,qb(this)))});if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])d.indexOf(" "+f+" ")<0&&(d+=f+" ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},removeClass:function(a){var b,c,d,e,f,g,h,i=0;if(r.isFunction(a))return this.each(function(b){r(this).removeClass(a.call(this,b,qb(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof a&&a){b=a.match(L)||[];while(c=this[i++])if(e=qb(c),d=1===c.nodeType&&" "+pb(e)+" "){g=0;while(f=b[g++])while(d.indexOf(" "+f+" ")>-1)d=d.replace(" "+f+" "," ");h=pb(d),e!==h&&c.setAttribute("class",h)}}return this},toggleClass:function(a,b){var c=typeof a;return"boolean"==typeof b&&"string"===c?b?this.addClass(a):this.removeClass(a):r.isFunction(a)?this.each(function(c){r(this).toggleClass(a.call(this,c,qb(this),b),b)}):this.each(function(){var b,d,e,f;if("string"===c){d=0,e=r(this),f=a.match(L)||[];while(b=f[d++])e.hasClass(b)?e.removeClass(b):e.addClass(b)}else void 0!==a&&"boolean"!==c||(b=qb(this),b&&W.set(this,"__className__",b),this.setAttribute&&this.setAttribute("class",b||a===!1?"":W.get(this,"__className__")||""))})},hasClass:function(a){var b,c,d=0;b=" "+a+" ";while(c=this[d++])if(1===c.nodeType&&(" "+pb(qb(c))+" ").indexOf(b)>-1)return!0;return!1}});var rb=/\r/g;r.fn.extend({val:function(a){var b,c,d,e=this[0];{if(arguments.length)return d=r.isFunction(a),this.each(function(c){var e;1===this.nodeType&&(e=d?a.call(this,c,r(this).val()):a,null==e?e="":"number"==typeof e?e+="":Array.isArray(e)&&(e=r.map(e,function(a){return null==a?"":a+""})),b=r.valHooks[this.type]||r.valHooks[this.nodeName.toLowerCase()],b&&"set"in b&&void 0!==b.set(this,e,"value")||(this.value=e))});if(e)return b=r.valHooks[e.type]||r.valHooks[e.nodeName.toLowerCase()],b&&"get"in b&&void 0!==(c=b.get(e,"value"))?c:(c=e.value,"string"==typeof c?c.replace(rb,""):null==c?"":c)}}}),r.extend({valHooks:{option:{get:function(a){var b=r.find.attr(a,"value");return null!=b?b:pb(r.text(a))}},select:{get:function(a){var b,c,d,e=a.options,f=a.selectedIndex,g="select-one"===a.type,h=g?null:[],i=g?f+1:e.length;for(d=f<0?i:g?f:0;d<i;d++)if(c=e[d],(c.selected||d===f)&&!c.disabled&&(!c.parentNode.disabled||!B(c.parentNode,"optgroup"))){if(b=r(c).val(),g)return b;h.push(b)}return h},set:function(a,b){var c,d,e=a.options,f=r.makeArray(b),g=e.length;while(g--)d=e[g],(d.selected=r.inArray(r.valHooks.option.get(d),f)>-1)&&(c=!0);return c||(a.selectedIndex=-1),f}}}}),r.each(["radio","checkbox"],function(){r.valHooks[this]={set:function(a,b){if(Array.isArray(b))return a.checked=r.inArray(r(a).val(),b)>-1}},o.checkOn||(r.valHooks[this].get=function(a){return null===a.getAttribute("value")?"on":a.value})});var sb=/^(?:focusinfocus|focusoutblur)$/;r.extend(r.event,{trigger:function(b,c,e,f){var g,h,i,j,k,m,n,o=[e||d],p=l.call(b,"type")?b.type:b,q=l.call(b,"namespace")?b.namespace.split("."):[];if(h=i=e=e||d,3!==e.nodeType&&8!==e.nodeType&&!sb.test(p+r.event.triggered)&&(p.indexOf(".")>-1&&(q=p.split("."),p=q.shift(),q.sort()),k=p.indexOf(":")<0&&"on"+p,b=b[r.expando]?b:new r.Event(p,"object"==typeof b&&b),b.isTrigger=f?2:3,b.namespace=q.join("."),b.rnamespace=b.namespace?new RegExp("(^|\\.)"+q.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,b.result=void 0,b.target||(b.target=e),c=null==c?[b]:r.makeArray(c,[b]),n=r.event.special[p]||{},f||!n.trigger||n.trigger.apply(e,c)!==!1)){if(!f&&!n.noBubble&&!r.isWindow(e)){for(j=n.delegateType||p,sb.test(j+p)||(h=h.parentNode);h;h=h.parentNode)o.push(h),i=h;i===(e.ownerDocument||d)&&o.push(i.defaultView||i.parentWindow||a)}g=0;while((h=o[g++])&&!b.isPropagationStopped())b.type=g>1?j:n.bindType||p,m=(W.get(h,"events")||{})[b.type]&&W.get(h,"handle"),m&&m.apply(h,c),m=k&&h[k],m&&m.apply&&U(h)&&(b.result=m.apply(h,c),b.result===!1&&b.preventDefault());return b.type=p,f||b.isDefaultPrevented()||n._default&&n._default.apply(o.pop(),c)!==!1||!U(e)||k&&r.isFunction(e[p])&&!r.isWindow(e)&&(i=e[k],i&&(e[k]=null),r.event.triggered=p,e[p](),r.event.triggered=void 0,i&&(e[k]=i)),b.result}},simulate:function(a,b,c){var d=r.extend(new r.Event,c,{type:a,isSimulated:!0});r.event.trigger(d,null,b)}}),r.fn.extend({trigger:function(a,b){return this.each(function(){r.event.trigger(a,b,this)})},triggerHandler:function(a,b){var c=this[0];if(c)return r.event.trigger(a,b,c,!0)}}),r.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(a,b){r.fn[b]=function(a,c){return arguments.length>0?this.on(b,null,a,c):this.trigger(b)}}),r.fn.extend({hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}}),o.focusin="onfocusin"in a,o.focusin||r.each({focus:"focusin",blur:"focusout"},function(a,b){var c=function(a){r.event.simulate(b,a.target,r.event.fix(a))};r.event.special[b]={setup:function(){var d=this.ownerDocument||this,e=W.access(d,b);e||d.addEventListener(a,c,!0),W.access(d,b,(e||0)+1)},teardown:function(){var d=this.ownerDocument||this,e=W.access(d,b)-1;e?W.access(d,b,e):(d.removeEventListener(a,c,!0),W.remove(d,b))}}});var tb=a.location,ub=r.now(),vb=/\?/;r.parseXML=function(b){var c;if(!b||"string"!=typeof b)return null;try{c=(new a.DOMParser).parseFromString(b,"text/xml")}catch(d){c=void 0}return c&&!c.getElementsByTagName("parsererror").length||r.error("Invalid XML: "+b),c};var wb=/\[\]$/,xb=/\r?\n/g,yb=/^(?:submit|button|image|reset|file)$/i,zb=/^(?:input|select|textarea|keygen)/i;function Ab(a,b,c,d){var e;if(Array.isArray(b))r.each(b,function(b,e){c||wb.test(a)?d(a,e):Ab(a+"["+("object"==typeof e&&null!=e?b:"")+"]",e,c,d)});else if(c||"object"!==r.type(b))d(a,b);else for(e in b)Ab(a+"["+e+"]",b[e],c,d)}r.param=function(a,b){var c,d=[],e=function(a,b){var c=r.isFunction(b)?b():b;d[d.length]=encodeURIComponent(a)+"="+encodeURIComponent(null==c?"":c)};if(Array.isArray(a)||a.jquery&&!r.isPlainObject(a))r.each(a,function(){e(this.name,this.value)});else for(c in a)Ab(c,a[c],b,e);return d.join("&")},r.fn.extend({serialize:function(){return r.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var a=r.prop(this,"elements");return a?r.makeArray(a):this}).filter(function(){var a=this.type;return this.name&&!r(this).is(":disabled")&&zb.test(this.nodeName)&&!yb.test(a)&&(this.checked||!ja.test(a))}).map(function(a,b){var c=r(this).val();return null==c?null:Array.isArray(c)?r.map(c,function(a){return{name:b.name,value:a.replace(xb,"\r\n")}}):{name:b.name,value:c.replace(xb,"\r\n")}}).get()}});var Bb=/%20/g,Cb=/#.*$/,Db=/([?&])_=[^&]*/,Eb=/^(.*?):[ \t]*([^\r\n]*)$/gm,Fb=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Gb=/^(?:GET|HEAD)$/,Hb=/^\/\//,Ib={},Jb={},Kb="*/".concat("*"),Lb=d.createElement("a");Lb.href=tb.href;function Mb(a){return function(b,c){"string"!=typeof b&&(c=b,b="*");var d,e=0,f=b.toLowerCase().match(L)||[];if(r.isFunction(c))while(d=f[e++])"+"===d[0]?(d=d.slice(1)||"*",(a[d]=a[d]||[]).unshift(c)):(a[d]=a[d]||[]).push(c)}}function Nb(a,b,c,d){var e={},f=a===Jb;function g(h){var i;return e[h]=!0,r.each(a[h]||[],function(a,h){var j=h(b,c,d);return"string"!=typeof j||f||e[j]?f?!(i=j):void 0:(b.dataTypes.unshift(j),g(j),!1)}),i}return g(b.dataTypes[0])||!e["*"]&&g("*")}function Ob(a,b){var c,d,e=r.ajaxSettings.flatOptions||{};for(c in b)void 0!==b[c]&&((e[c]?a:d||(d={}))[c]=b[c]);return d&&r.extend(!0,a,d),a}function Pb(a,b,c){var d,e,f,g,h=a.contents,i=a.dataTypes;while("*"===i[0])i.shift(),void 0===d&&(d=a.mimeType||b.getResponseHeader("Content-Type"));if(d)for(e in h)if(h[e]&&h[e].test(d)){i.unshift(e);break}if(i[0]in c)f=i[0];else{for(e in c){if(!i[0]||a.converters[e+" "+i[0]]){f=e;break}g||(g=e)}f=f||g}if(f)return f!==i[0]&&i.unshift(f),c[f]}function Qb(a,b,c,d){var e,f,g,h,i,j={},k=a.dataTypes.slice();if(k[1])for(g in a.converters)j[g.toLowerCase()]=a.converters[g];f=k.shift();while(f)if(a.responseFields[f]&&(c[a.responseFields[f]]=b),!i&&d&&a.dataFilter&&(b=a.dataFilter(b,a.dataType)),i=f,f=k.shift())if("*"===f)f=i;else if("*"!==i&&i!==f){if(g=j[i+" "+f]||j["* "+f],!g)for(e in j)if(h=e.split(" "),h[1]===f&&(g=j[i+" "+h[0]]||j["* "+h[0]])){g===!0?g=j[e]:j[e]!==!0&&(f=h[0],k.unshift(h[1]));break}if(g!==!0)if(g&&a["throws"])b=g(b);else try{b=g(b)}catch(l){return{state:"parsererror",error:g?l:"No conversion from "+i+" to "+f}}}return{state:"success",data:b}}r.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:tb.href,type:"GET",isLocal:Fb.test(tb.protocol),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Kb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/\bxml\b/,html:/\bhtml/,json:/\bjson\b/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":JSON.parse,"text xml":r.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?Ob(Ob(a,r.ajaxSettings),b):Ob(r.ajaxSettings,a)},ajaxPrefilter:Mb(Ib),ajaxTransport:Mb(Jb),ajax:function(b,c){"object"==typeof b&&(c=b,b=void 0),c=c||{};var e,f,g,h,i,j,k,l,m,n,o=r.ajaxSetup({},c),p=o.context||o,q=o.context&&(p.nodeType||p.jquery)?r(p):r.event,s=r.Deferred(),t=r.Callbacks("once memory"),u=o.statusCode||{},v={},w={},x="canceled",y={readyState:0,getResponseHeader:function(a){var b;if(k){if(!h){h={};while(b=Eb.exec(g))h[b[1].toLowerCase()]=b[2]}b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return k?g:null},setRequestHeader:function(a,b){return null==k&&(a=w[a.toLowerCase()]=w[a.toLowerCase()]||a,v[a]=b),this},overrideMimeType:function(a){return null==k&&(o.mimeType=a),this},statusCode:function(a){var b;if(a)if(k)y.always(a[y.status]);else for(b in a)u[b]=[u[b],a[b]];return this},abort:function(a){var b=a||x;return e&&e.abort(b),A(0,b),this}};if(s.promise(y),o.url=((b||o.url||tb.href)+"").replace(Hb,tb.protocol+"//"),o.type=c.method||c.type||o.method||o.type,o.dataTypes=(o.dataType||"*").toLowerCase().match(L)||[""],null==o.crossDomain){j=d.createElement("a");try{j.href=o.url,j.href=j.href,o.crossDomain=Lb.protocol+"//"+Lb.host!=j.protocol+"//"+j.host}catch(z){o.crossDomain=!0}}if(o.data&&o.processData&&"string"!=typeof o.data&&(o.data=r.param(o.data,o.traditional)),Nb(Ib,o,c,y),k)return y;l=r.event&&o.global,l&&0===r.active++&&r.event.trigger("ajaxStart"),o.type=o.type.toUpperCase(),o.hasContent=!Gb.test(o.type),f=o.url.replace(Cb,""),o.hasContent?o.data&&o.processData&&0===(o.contentType||"").indexOf("application/x-www-form-urlencoded")&&(o.data=o.data.replace(Bb,"+")):(n=o.url.slice(f.length),o.data&&(f+=(vb.test(f)?"&":"?")+o.data,delete o.data),o.cache===!1&&(f=f.replace(Db,"$1"),n=(vb.test(f)?"&":"?")+"_="+ub++ +n),o.url=f+n),o.ifModified&&(r.lastModified[f]&&y.setRequestHeader("If-Modified-Since",r.lastModified[f]),r.etag[f]&&y.setRequestHeader("If-None-Match",r.etag[f])),(o.data&&o.hasContent&&o.contentType!==!1||c.contentType)&&y.setRequestHeader("Content-Type",o.contentType),y.setRequestHeader("Accept",o.dataTypes[0]&&o.accepts[o.dataTypes[0]]?o.accepts[o.dataTypes[0]]+("*"!==o.dataTypes[0]?", "+Kb+"; q=0.01":""):o.accepts["*"]);for(m in o.headers)y.setRequestHeader(m,o.headers[m]);if(o.beforeSend&&(o.beforeSend.call(p,y,o)===!1||k))return y.abort();if(x="abort",t.add(o.complete),y.done(o.success),y.fail(o.error),e=Nb(Jb,o,c,y)){if(y.readyState=1,l&&q.trigger("ajaxSend",[y,o]),k)return y;o.async&&o.timeout>0&&(i=a.setTimeout(function(){y.abort("timeout")},o.timeout));try{k=!1,e.send(v,A)}catch(z){if(k)throw z;A(-1,z)}}else A(-1,"No Transport");function A(b,c,d,h){var j,m,n,v,w,x=c;k||(k=!0,i&&a.clearTimeout(i),e=void 0,g=h||"",y.readyState=b>0?4:0,j=b>=200&&b<300||304===b,d&&(v=Pb(o,y,d)),v=Qb(o,v,y,j),j?(o.ifModified&&(w=y.getResponseHeader("Last-Modified"),w&&(r.lastModified[f]=w),w=y.getResponseHeader("etag"),w&&(r.etag[f]=w)),204===b||"HEAD"===o.type?x="nocontent":304===b?x="notmodified":(x=v.state,m=v.data,n=v.error,j=!n)):(n=x,!b&&x||(x="error",b<0&&(b=0))),y.status=b,y.statusText=(c||x)+"",j?s.resolveWith(p,[m,x,y]):s.rejectWith(p,[y,x,n]),y.statusCode(u),u=void 0,l&&q.trigger(j?"ajaxSuccess":"ajaxError",[y,o,j?m:n]),t.fireWith(p,[y,x]),l&&(q.trigger("ajaxComplete",[y,o]),--r.active||r.event.trigger("ajaxStop")))}return y},getJSON:function(a,b,c){return r.get(a,b,c,"json")},getScript:function(a,b){return r.get(a,void 0,b,"script")}}),r.each(["get","post"],function(a,b){r[b]=function(a,c,d,e){return r.isFunction(c)&&(e=e||d,d=c,c=void 0),r.ajax(r.extend({url:a,type:b,dataType:e,data:c,success:d},r.isPlainObject(a)&&a))}}),r._evalUrl=function(a){return r.ajax({url:a,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},r.fn.extend({wrapAll:function(a){var b;return this[0]&&(r.isFunction(a)&&(a=a.call(this[0])),b=r(a,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&b.insertBefore(this[0]),b.map(function(){var a=this;while(a.firstElementChild)a=a.firstElementChild;return a}).append(this)),this},wrapInner:function(a){return r.isFunction(a)?this.each(function(b){r(this).wrapInner(a.call(this,b))}):this.each(function(){var b=r(this),c=b.contents();c.length?c.wrapAll(a):b.append(a)})},wrap:function(a){var b=r.isFunction(a);return this.each(function(c){r(this).wrapAll(b?a.call(this,c):a)})},unwrap:function(a){return this.parent(a).not("body").each(function(){r(this).replaceWith(this.childNodes)}),this}}),r.expr.pseudos.hidden=function(a){return!r.expr.pseudos.visible(a)},r.expr.pseudos.visible=function(a){return!!(a.offsetWidth||a.offsetHeight||a.getClientRects().length)},r.ajaxSettings.xhr=function(){try{return new a.XMLHttpRequest}catch(b){}};var Rb={0:200,1223:204},Sb=r.ajaxSettings.xhr();o.cors=!!Sb&&"withCredentials"in Sb,o.ajax=Sb=!!Sb,r.ajaxTransport(function(b){var c,d;if(o.cors||Sb&&!b.crossDomain)return{send:function(e,f){var g,h=b.xhr();if(h.open(b.type,b.url,b.async,b.username,b.password),b.xhrFields)for(g in b.xhrFields)h[g]=b.xhrFields[g];b.mimeType&&h.overrideMimeType&&h.overrideMimeType(b.mimeType),b.crossDomain||e["X-Requested-With"]||(e["X-Requested-With"]="XMLHttpRequest");for(g in e)h.setRequestHeader(g,e[g]);c=function(a){return function(){c&&(c=d=h.onload=h.onerror=h.onabort=h.onreadystatechange=null,"abort"===a?h.abort():"error"===a?"number"!=typeof h.status?f(0,"error"):f(h.status,h.statusText):f(Rb[h.status]||h.status,h.statusText,"text"!==(h.responseType||"text")||"string"!=typeof h.responseText?{binary:h.response}:{text:h.responseText},h.getAllResponseHeaders()))}},h.onload=c(),d=h.onerror=c("error"),void 0!==h.onabort?h.onabort=d:h.onreadystatechange=function(){4===h.readyState&&a.setTimeout(function(){c&&d()})},c=c("abort");try{h.send(b.hasContent&&b.data||null)}catch(i){if(c)throw i}},abort:function(){c&&c()}}}),r.ajaxPrefilter(function(a){a.crossDomain&&(a.contents.script=!1)}),r.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/\b(?:java|ecma)script\b/},converters:{"text script":function(a){return r.globalEval(a),a}}}),r.ajaxPrefilter("script",function(a){void 0===a.cache&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),r.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(e,f){b=r("<script>").prop({charset:a.scriptCharset,src:a.url}).on("load error",c=function(a){b.remove(),c=null,a&&f("error"===a.type?404:200,a.type)}),d.head.appendChild(b[0])},abort:function(){c&&c()}}}});var Tb=[],Ub=/(=)\?(?=&|$)|\?\?/;r.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var a=Tb.pop()||r.expando+"_"+ub++;return this[a]=!0,a}}),r.ajaxPrefilter("json jsonp",function(b,c,d){var e,f,g,h=b.jsonp!==!1&&(Ub.test(b.url)?"url":"string"==typeof b.data&&0===(b.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ub.test(b.data)&&"data");if(h||"jsonp"===b.dataTypes[0])return e=b.jsonpCallback=r.isFunction(b.jsonpCallback)?b.jsonpCallback():b.jsonpCallback,h?b[h]=b[h].replace(Ub,"$1"+e):b.jsonp!==!1&&(b.url+=(vb.test(b.url)?"&":"?")+b.jsonp+"="+e),b.converters["script json"]=function(){return g||r.error(e+" was not called"),g[0]},b.dataTypes[0]="json",f=a[e],a[e]=function(){g=arguments},d.always(function(){void 0===f?r(a).removeProp(e):a[e]=f,b[e]&&(b.jsonpCallback=c.jsonpCallback,Tb.push(e)),g&&r.isFunction(f)&&f(g[0]),g=f=void 0}),"script"}),o.createHTMLDocument=function(){var a=d.implementation.createHTMLDocument("").body;return a.innerHTML="<form></form><form></form>",2===a.childNodes.length}(),r.parseHTML=function(a,b,c){if("string"!=typeof a)return[];"boolean"==typeof b&&(c=b,b=!1);var e,f,g;return b||(o.createHTMLDocument?(b=d.implementation.createHTMLDocument(""),e=b.createElement("base"),e.href=d.location.href,b.head.appendChild(e)):b=d),f=C.exec(a),g=!c&&[],f?[b.createElement(f[1])]:(f=qa([a],b,g),g&&g.length&&r(g).remove(),r.merge([],f.childNodes))},r.fn.load=function(a,b,c){var d,e,f,g=this,h=a.indexOf(" ");return h>-1&&(d=pb(a.slice(h)),a=a.slice(0,h)),r.isFunction(b)?(c=b,b=void 0):b&&"object"==typeof b&&(e="POST"),g.length>0&&r.ajax({url:a,type:e||"GET",dataType:"html",data:b}).done(function(a){f=arguments,g.html(d?r("<div>").append(r.parseHTML(a)).find(d):a)}).always(c&&function(a,b){g.each(function(){c.apply(this,f||[a.responseText,b,a])})}),this},r.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){r.fn[b]=function(a){return this.on(b,a)}}),r.expr.pseudos.animated=function(a){return r.grep(r.timers,function(b){return a===b.elem}).length},r.offset={setOffset:function(a,b,c){var d,e,f,g,h,i,j,k=r.css(a,"position"),l=r(a),m={};"static"===k&&(a.style.position="relative"),h=l.offset(),f=r.css(a,"top"),i=r.css(a,"left"),j=("absolute"===k||"fixed"===k)&&(f+i).indexOf("auto")>-1,j?(d=l.position(),g=d.top,e=d.left):(g=parseFloat(f)||0,e=parseFloat(i)||0),r.isFunction(b)&&(b=b.call(a,c,r.extend({},h))),null!=b.top&&(m.top=b.top-h.top+g),null!=b.left&&(m.left=b.left-h.left+e),"using"in b?b.using.call(a,m):l.css(m)}},r.fn.extend({offset:function(a){if(arguments.length)return void 0===a?this:this.each(function(b){r.offset.setOffset(this,a,b)});var b,c,d,e,f=this[0];if(f)return f.getClientRects().length?(d=f.getBoundingClientRect(),b=f.ownerDocument,c=b.documentElement,e=b.defaultView,{top:d.top+e.pageYOffset-c.clientTop,left:d.left+e.pageXOffset-c.clientLeft}):{top:0,left:0}},position:function(){if(this[0]){var a,b,c=this[0],d={top:0,left:0};return"fixed"===r.css(c,"position")?b=c.getBoundingClientRect():(a=this.offsetParent(),b=this.offset(),B(a[0],"html")||(d=a.offset()),d={top:d.top+r.css(a[0],"borderTopWidth",!0),left:d.left+r.css(a[0],"borderLeftWidth",!0)}),{top:b.top-d.top-r.css(c,"marginTop",!0),left:b.left-d.left-r.css(c,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var a=this.offsetParent;while(a&&"static"===r.css(a,"position"))a=a.offsetParent;return a||ra})}}),r.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(a,b){var c="pageYOffset"===b;r.fn[a]=function(d){return T(this,function(a,d,e){var f;return r.isWindow(a)?f=a:9===a.nodeType&&(f=a.defaultView),void 0===e?f?f[b]:a[d]:void(f?f.scrollTo(c?f.pageXOffset:e,c?e:f.pageYOffset):a[d]=e)},a,d,arguments.length)}}),r.each(["top","left"],function(a,b){r.cssHooks[b]=Pa(o.pixelPosition,function(a,c){if(c)return c=Oa(a,b),Ma.test(c)?r(a).position()[b]+"px":c})}),r.each({Height:"height",Width:"width"},function(a,b){r.each({padding:"inner"+a,content:b,"":"outer"+a},function(c,d){r.fn[d]=function(e,f){var g=arguments.length&&(c||"boolean"!=typeof e),h=c||(e===!0||f===!0?"margin":"border");return T(this,function(b,c,e){var f;return r.isWindow(b)?0===d.indexOf("outer")?b["inner"+a]:b.document.documentElement["client"+a]:9===b.nodeType?(f=b.documentElement,Math.max(b.body["scroll"+a],f["scroll"+a],b.body["offset"+a],f["offset"+a],f["client"+a])):void 0===e?r.css(b,c,h):r.style(b,c,e,h)},b,g?e:void 0,g)}})}),r.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),r.holdReady=function(a){a?r.readyWait++:r.ready(!0)},r.isArray=Array.isArray,r.parseJSON=JSON.parse,r.nodeName=B,"function"==typeof define&&define.amd&&define("jquery",[],function(){return r});var Vb=a.jQuery,Wb=a.$;return r.noConflict=function(b){return a.$===r&&(a.$=Wb),b&&a.jQuery===r&&(a.jQuery=Vb),r},b||(a.jQuery=a.$=r),r});
src/arborator-draft/jszip.min.js ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /*!
2
+
3
+ JSZip v3.3.0 - A JavaScript class for generating and reading zip files
4
+ <http://stuartk.com/jszip>
5
+
6
+ (c) 2009-2016 Stuart Knightley <stuart [at] stuartk.com>
7
+ Dual licenced under the MIT license or GPLv3. See https://raw.github.com/Stuk/jszip/master/LICENSE.markdown.
8
+
9
+ JSZip uses the library pako released under the MIT license :
10
+ https://github.com/nodeca/pako/blob/master/LICENSE
11
+ */
12
+
13
+ !function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).JSZip=t()}}(function(){return function s(a,o,h){function u(r,t){if(!o[r]){if(!a[r]){var e="function"==typeof require&&require;if(!t&&e)return e(r,!0);if(l)return l(r,!0);var i=new Error("Cannot find module '"+r+"'");throw i.code="MODULE_NOT_FOUND",i}var n=o[r]={exports:{}};a[r][0].call(n.exports,function(t){var e=a[r][1][t];return u(e||t)},n,n.exports,s,a,o,h)}return o[r].exports}for(var l="function"==typeof require&&require,t=0;t<h.length;t++)u(h[t]);return u}({1:[function(t,e,r){"use strict";var c=t("./utils"),d=t("./support"),p="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";r.encode=function(t){for(var e,r,i,n,s,a,o,h=[],u=0,l=t.length,f=l,d="string"!==c.getTypeOf(t);u<t.length;)f=l-u,i=d?(e=t[u++],r=u<l?t[u++]:0,u<l?t[u++]:0):(e=t.charCodeAt(u++),r=u<l?t.charCodeAt(u++):0,u<l?t.charCodeAt(u++):0),n=e>>2,s=(3&e)<<4|r>>4,a=1<f?(15&r)<<2|i>>6:64,o=2<f?63&i:64,h.push(p.charAt(n)+p.charAt(s)+p.charAt(a)+p.charAt(o));return h.join("")},r.decode=function(t){var e,r,i,n,s,a,o=0,h=0,u="data:";if(t.substr(0,u.length)===u)throw new Error("Invalid base64 input, it looks like a data url.");var l,f=3*(t=t.replace(/[^A-Za-z0-9\+\/\=]/g,"")).length/4;if(t.charAt(t.length-1)===p.charAt(64)&&f--,t.charAt(t.length-2)===p.charAt(64)&&f--,f%1!=0)throw new Error("Invalid base64 input, bad content length.");for(l=d.uint8array?new Uint8Array(0|f):new Array(0|f);o<t.length;)e=p.indexOf(t.charAt(o++))<<2|(n=p.indexOf(t.charAt(o++)))>>4,r=(15&n)<<4|(s=p.indexOf(t.charAt(o++)))>>2,i=(3&s)<<6|(a=p.indexOf(t.charAt(o++))),l[h++]=e,64!==s&&(l[h++]=r),64!==a&&(l[h++]=i);return l}},{"./support":30,"./utils":32}],2:[function(t,e,r){"use strict";var i=t("./external"),n=t("./stream/DataWorker"),s=t("./stream/DataLengthProbe"),a=t("./stream/Crc32Probe");s=t("./stream/DataLengthProbe");function o(t,e,r,i,n){this.compressedSize=t,this.uncompressedSize=e,this.crc32=r,this.compression=i,this.compressedContent=n}o.prototype={getContentWorker:function(){var t=new n(i.Promise.resolve(this.compressedContent)).pipe(this.compression.uncompressWorker()).pipe(new s("data_length")),e=this;return t.on("end",function(){if(this.streamInfo.data_length!==e.uncompressedSize)throw new Error("Bug : uncompressed data size mismatch")}),t},getCompressedWorker:function(){return new n(i.Promise.resolve(this.compressedContent)).withStreamInfo("compressedSize",this.compressedSize).withStreamInfo("uncompressedSize",this.uncompressedSize).withStreamInfo("crc32",this.crc32).withStreamInfo("compression",this.compression)}},o.createWorkerFrom=function(t,e,r){return t.pipe(new a).pipe(new s("uncompressedSize")).pipe(e.compressWorker(r)).pipe(new s("compressedSize")).withStreamInfo("compression",e)},e.exports=o},{"./external":6,"./stream/Crc32Probe":25,"./stream/DataLengthProbe":26,"./stream/DataWorker":27}],3:[function(t,e,r){"use strict";var i=t("./stream/GenericWorker");r.STORE={magic:"\0\0",compressWorker:function(t){return new i("STORE compression")},uncompressWorker:function(){return new i("STORE decompression")}},r.DEFLATE=t("./flate")},{"./flate":7,"./stream/GenericWorker":28}],4:[function(t,e,r){"use strict";var i=t("./utils");var o=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e){return void 0!==t&&t.length?"string"!==i.getTypeOf(t)?function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e[a])];return-1^t}(0|e,t,t.length,0):function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e.charCodeAt(a))];return-1^t}(0|e,t,t.length,0):0}},{"./utils":32}],5:[function(t,e,r){"use strict";r.base64=!1,r.binary=!1,r.dir=!1,r.createFolders=!0,r.date=null,r.compression=null,r.compressionOptions=null,r.comment=null,r.unixPermissions=null,r.dosPermissions=null},{}],6:[function(t,e,r){"use strict";var i=null;i="undefined"!=typeof Promise?Promise:t("lie"),e.exports={Promise:i}},{lie:37}],7:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Uint32Array,n=t("pako"),s=t("./utils"),a=t("./stream/GenericWorker"),o=i?"uint8array":"array";function h(t,e){a.call(this,"FlateWorker/"+t),this._pako=null,this._pakoAction=t,this._pakoOptions=e,this.meta={}}r.magic="\b\0",s.inherits(h,a),h.prototype.processChunk=function(t){this.meta=t.meta,null===this._pako&&this._createPako(),this._pako.push(s.transformTo(o,t.data),!1)},h.prototype.flush=function(){a.prototype.flush.call(this),null===this._pako&&this._createPako(),this._pako.push([],!0)},h.prototype.cleanUp=function(){a.prototype.cleanUp.call(this),this._pako=null},h.prototype._createPako=function(){this._pako=new n[this._pakoAction]({raw:!0,level:this._pakoOptions.level||-1});var e=this;this._pako.onData=function(t){e.push({data:t,meta:e.meta})}},r.compressWorker=function(t){return new h("Deflate",t)},r.uncompressWorker=function(){return new h("Inflate",{})}},{"./stream/GenericWorker":28,"./utils":32,pako:38}],8:[function(t,e,r){"use strict";function A(t,e){var r,i="";for(r=0;r<e;r++)i+=String.fromCharCode(255&t),t>>>=8;return i}function i(t,e,r,i,n,s){var a,o,h=t.file,u=t.compression,l=s!==O.utf8encode,f=I.transformTo("string",s(h.name)),d=I.transformTo("string",O.utf8encode(h.name)),c=h.comment,p=I.transformTo("string",s(c)),m=I.transformTo("string",O.utf8encode(c)),_=d.length!==h.name.length,g=m.length!==c.length,b="",v="",y="",w=h.dir,k=h.date,x={crc32:0,compressedSize:0,uncompressedSize:0};e&&!r||(x.crc32=t.crc32,x.compressedSize=t.compressedSize,x.uncompressedSize=t.uncompressedSize);var S=0;e&&(S|=8),l||!_&&!g||(S|=2048);var z=0,C=0;w&&(z|=16),"UNIX"===n?(C=798,z|=function(t,e){var r=t;return t||(r=e?16893:33204),(65535&r)<<16}(h.unixPermissions,w)):(C=20,z|=function(t){return 63&(t||0)}(h.dosPermissions)),a=k.getUTCHours(),a<<=6,a|=k.getUTCMinutes(),a<<=5,a|=k.getUTCSeconds()/2,o=k.getUTCFullYear()-1980,o<<=4,o|=k.getUTCMonth()+1,o<<=5,o|=k.getUTCDate(),_&&(v=A(1,1)+A(B(f),4)+d,b+="up"+A(v.length,2)+v),g&&(y=A(1,1)+A(B(p),4)+m,b+="uc"+A(y.length,2)+y);var E="";return E+="\n\0",E+=A(S,2),E+=u.magic,E+=A(a,2),E+=A(o,2),E+=A(x.crc32,4),E+=A(x.compressedSize,4),E+=A(x.uncompressedSize,4),E+=A(f.length,2),E+=A(b.length,2),{fileRecord:R.LOCAL_FILE_HEADER+E+f+b,dirRecord:R.CENTRAL_FILE_HEADER+A(C,2)+E+A(p.length,2)+"\0\0\0\0"+A(z,4)+A(i,4)+f+b+p}}var I=t("../utils"),n=t("../stream/GenericWorker"),O=t("../utf8"),B=t("../crc32"),R=t("../signature");function s(t,e,r,i){n.call(this,"ZipFileWorker"),this.bytesWritten=0,this.zipComment=e,this.zipPlatform=r,this.encodeFileName=i,this.streamFiles=t,this.accumulate=!1,this.contentBuffer=[],this.dirRecords=[],this.currentSourceOffset=0,this.entriesCount=0,this.currentFile=null,this._sources=[]}I.inherits(s,n),s.prototype.push=function(t){var e=t.meta.percent||0,r=this.entriesCount,i=this._sources.length;this.accumulate?this.contentBuffer.push(t):(this.bytesWritten+=t.data.length,n.prototype.push.call(this,{data:t.data,meta:{currentFile:this.currentFile,percent:r?(e+100*(r-i-1))/r:100}}))},s.prototype.openedSource=function(t){this.currentSourceOffset=this.bytesWritten,this.currentFile=t.file.name;var e=this.streamFiles&&!t.file.dir;if(e){var r=i(t,e,!1,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);this.push({data:r.fileRecord,meta:{percent:0}})}else this.accumulate=!0},s.prototype.closedSource=function(t){this.accumulate=!1;var e=this.streamFiles&&!t.file.dir,r=i(t,e,!0,this.currentSourceOffset,this.zipPlatform,this.encodeFileName);if(this.dirRecords.push(r.dirRecord),e)this.push({data:function(t){return R.DATA_DESCRIPTOR+A(t.crc32,4)+A(t.compressedSize,4)+A(t.uncompressedSize,4)}(t),meta:{percent:100}});else for(this.push({data:r.fileRecord,meta:{percent:0}});this.contentBuffer.length;)this.push(this.contentBuffer.shift());this.currentFile=null},s.prototype.flush=function(){for(var t=this.bytesWritten,e=0;e<this.dirRecords.length;e++)this.push({data:this.dirRecords[e],meta:{percent:100}});var r=this.bytesWritten-t,i=function(t,e,r,i,n){var s=I.transformTo("string",n(i));return R.CENTRAL_DIRECTORY_END+"\0\0\0\0"+A(t,2)+A(t,2)+A(e,4)+A(r,4)+A(s.length,2)+s}(this.dirRecords.length,r,t,this.zipComment,this.encodeFileName);this.push({data:i,meta:{percent:100}})},s.prototype.prepareNextSource=function(){this.previous=this._sources.shift(),this.openedSource(this.previous.streamInfo),this.isPaused?this.previous.pause():this.previous.resume()},s.prototype.registerPrevious=function(t){this._sources.push(t);var e=this;return t.on("data",function(t){e.processChunk(t)}),t.on("end",function(){e.closedSource(e.previous.streamInfo),e._sources.length?e.prepareNextSource():e.end()}),t.on("error",function(t){e.error(t)}),this},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this.previous&&this._sources.length?(this.prepareNextSource(),!0):this.previous||this._sources.length||this.generatedError?void 0:(this.end(),!0))},s.prototype.error=function(t){var e=this._sources;if(!n.prototype.error.call(this,t))return!1;for(var r=0;r<e.length;r++)try{e[r].error(t)}catch(t){}return!0},s.prototype.lock=function(){n.prototype.lock.call(this);for(var t=this._sources,e=0;e<t.length;e++)t[e].lock()},e.exports=s},{"../crc32":4,"../signature":23,"../stream/GenericWorker":28,"../utf8":31,"../utils":32}],9:[function(t,e,r){"use strict";var u=t("../compressions"),i=t("./ZipFileWorker");r.generateWorker=function(t,a,e){var o=new i(a.streamFiles,e,a.platform,a.encodeFileName),h=0;try{t.forEach(function(t,e){h++;var r=function(t,e){var r=t||e,i=u[r];if(!i)throw new Error(r+" is not a valid compression method !");return i}(e.options.compression,a.compression),i=e.options.compressionOptions||a.compressionOptions||{},n=e.dir,s=e.date;e._compressWorker(r,i).withStreamInfo("file",{name:t,dir:n,date:s,comment:e.comment||"",unixPermissions:e.unixPermissions,dosPermissions:e.dosPermissions}).pipe(o)}),o.entriesCount=h}catch(t){o.error(t)}return o}},{"../compressions":3,"./ZipFileWorker":8}],10:[function(t,e,r){"use strict";function i(){if(!(this instanceof i))return new i;if(arguments.length)throw new Error("The constructor with parameters has been removed in JSZip 3.0, please check the upgrade guide.");this.files={},this.comment=null,this.root="",this.clone=function(){var t=new i;for(var e in this)"function"!=typeof this[e]&&(t[e]=this[e]);return t}}(i.prototype=t("./object")).loadAsync=t("./load"),i.support=t("./support"),i.defaults=t("./defaults"),i.version="3.4.0",i.loadAsync=function(t,e){return(new i).loadAsync(t,e)},i.external=t("./external"),e.exports=i},{"./defaults":5,"./external":6,"./load":11,"./object":15,"./support":30}],11:[function(t,e,r){"use strict";var i=t("./utils"),n=t("./external"),o=t("./utf8"),h=(i=t("./utils"),t("./zipEntries")),s=t("./stream/Crc32Probe"),u=t("./nodejsUtils");function l(i){return new n.Promise(function(t,e){var r=i.decompressed.getContentWorker().pipe(new s);r.on("error",function(t){e(t)}).on("end",function(){r.streamInfo.crc32!==i.decompressed.crc32?e(new Error("Corrupted zip : CRC32 mismatch")):t()}).resume()})}e.exports=function(t,s){var a=this;return s=i.extend(s||{},{base64:!1,checkCRC32:!1,optimizedBinaryString:!1,createFolders:!1,decodeFileName:o.utf8decode}),u.isNode&&u.isStream(t)?n.Promise.reject(new Error("JSZip can't accept a stream when loading a zip file.")):i.prepareContent("the loaded zip file",t,!0,s.optimizedBinaryString,s.base64).then(function(t){var e=new h(s);return e.load(t),e}).then(function(t){var e=[n.Promise.resolve(t)],r=t.files;if(s.checkCRC32)for(var i=0;i<r.length;i++)e.push(l(r[i]));return n.Promise.all(e)}).then(function(t){for(var e=t.shift(),r=e.files,i=0;i<r.length;i++){var n=r[i];a.file(n.fileNameStr,n.decompressed,{binary:!0,optimizedBinaryString:!0,date:n.date,dir:n.dir,comment:n.fileCommentStr.length?n.fileCommentStr:null,unixPermissions:n.unixPermissions,dosPermissions:n.dosPermissions,createFolders:s.createFolders})}return e.zipComment.length&&(a.comment=e.zipComment),a})}},{"./external":6,"./nodejsUtils":14,"./stream/Crc32Probe":25,"./utf8":31,"./utils":32,"./zipEntries":33}],12:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../stream/GenericWorker");function s(t,e){n.call(this,"Nodejs stream input adapter for "+t),this._upstreamEnded=!1,this._bindStream(e)}i.inherits(s,n),s.prototype._bindStream=function(t){var e=this;(this._stream=t).pause(),t.on("data",function(t){e.push({data:t,meta:{percent:0}})}).on("error",function(t){e.isPaused?this.generatedError=t:e.error(t)}).on("end",function(){e.isPaused?e._upstreamEnded=!0:e.end()})},s.prototype.pause=function(){return!!n.prototype.pause.call(this)&&(this._stream.pause(),!0)},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(this._upstreamEnded?this.end():this._stream.resume(),!0)},e.exports=s},{"../stream/GenericWorker":28,"../utils":32}],13:[function(t,e,r){"use strict";var n=t("readable-stream").Readable;function i(t,e,r){n.call(this,e),this._helper=t;var i=this;t.on("data",function(t,e){i.push(t)||i._helper.pause(),r&&r(e)}).on("error",function(t){i.emit("error",t)}).on("end",function(){i.push(null)})}t("../utils").inherits(i,n),i.prototype._read=function(){this._helper.resume()},e.exports=i},{"../utils":32,"readable-stream":16}],14:[function(t,e,r){"use strict";e.exports={isNode:"undefined"!=typeof Buffer,newBufferFrom:function(t,e){if(Buffer.from&&Buffer.from!==Uint8Array.from)return Buffer.from(t,e);if("number"==typeof t)throw new Error('The "data" argument must not be a number');return new Buffer(t,e)},allocBuffer:function(t){if(Buffer.alloc)return Buffer.alloc(t);var e=new Buffer(t);return e.fill(0),e},isBuffer:function(t){return Buffer.isBuffer(t)},isStream:function(t){return t&&"function"==typeof t.on&&"function"==typeof t.pause&&"function"==typeof t.resume}}},{}],15:[function(t,e,r){"use strict";function s(t,e,r){var i,n=u.getTypeOf(e),s=u.extend(r||{},f);s.date=s.date||new Date,null!==s.compression&&(s.compression=s.compression.toUpperCase()),"string"==typeof s.unixPermissions&&(s.unixPermissions=parseInt(s.unixPermissions,8)),s.unixPermissions&&16384&s.unixPermissions&&(s.dir=!0),s.dosPermissions&&16&s.dosPermissions&&(s.dir=!0),s.dir&&(t=g(t)),s.createFolders&&(i=_(t))&&b.call(this,i,!0);var a="string"===n&&!1===s.binary&&!1===s.base64;r&&void 0!==r.binary||(s.binary=!a),(e instanceof d&&0===e.uncompressedSize||s.dir||!e||0===e.length)&&(s.base64=!1,s.binary=!0,e="",s.compression="STORE",n="string");var o=null;o=e instanceof d||e instanceof l?e:p.isNode&&p.isStream(e)?new m(t,e):u.prepareContent(t,e,s.binary,s.optimizedBinaryString,s.base64);var h=new c(t,o,s);this.files[t]=h}var n=t("./utf8"),u=t("./utils"),l=t("./stream/GenericWorker"),a=t("./stream/StreamHelper"),f=t("./defaults"),d=t("./compressedObject"),c=t("./zipObject"),o=t("./generate"),p=t("./nodejsUtils"),m=t("./nodejs/NodejsStreamInputAdapter"),_=function(t){"/"===t.slice(-1)&&(t=t.substring(0,t.length-1));var e=t.lastIndexOf("/");return 0<e?t.substring(0,e):""},g=function(t){return"/"!==t.slice(-1)&&(t+="/"),t},b=function(t,e){return e=void 0!==e?e:f.createFolders,t=g(t),this.files[t]||s.call(this,t,null,{dir:!0,createFolders:e}),this.files[t]};function h(t){return"[object RegExp]"===Object.prototype.toString.call(t)}var i={load:function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},forEach:function(t){var e,r,i;for(e in this.files)this.files.hasOwnProperty(e)&&(i=this.files[e],(r=e.slice(this.root.length,e.length))&&e.slice(0,this.root.length)===this.root&&t(r,i))},filter:function(r){var i=[];return this.forEach(function(t,e){r(t,e)&&i.push(e)}),i},file:function(t,e,r){if(1!==arguments.length)return t=this.root+t,s.call(this,t,e,r),this;if(h(t)){var i=t;return this.filter(function(t,e){return!e.dir&&i.test(t)})}var n=this.files[this.root+t];return n&&!n.dir?n:null},folder:function(r){if(!r)return this;if(h(r))return this.filter(function(t,e){return e.dir&&r.test(t)});var t=this.root+r,e=b.call(this,t),i=this.clone();return i.root=e.name,i},remove:function(r){r=this.root+r;var t=this.files[r];if(t||("/"!==r.slice(-1)&&(r+="/"),t=this.files[r]),t&&!t.dir)delete this.files[r];else for(var e=this.filter(function(t,e){return e.name.slice(0,r.length)===r}),i=0;i<e.length;i++)delete this.files[e[i].name];return this},generate:function(t){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},generateInternalStream:function(t){var e,r={};try{if((r=u.extend(t||{},{streamFiles:!1,compression:"STORE",compressionOptions:null,type:"",platform:"DOS",comment:null,mimeType:"application/zip",encodeFileName:n.utf8encode})).type=r.type.toLowerCase(),r.compression=r.compression.toUpperCase(),"binarystring"===r.type&&(r.type="string"),!r.type)throw new Error("No output type specified.");u.checkSupport(r.type),"darwin"!==r.platform&&"freebsd"!==r.platform&&"linux"!==r.platform&&"sunos"!==r.platform||(r.platform="UNIX"),"win32"===r.platform&&(r.platform="DOS");var i=r.comment||this.comment||"";e=o.generateWorker(this,r,i)}catch(t){(e=new l("error")).error(t)}return new a(e,r.type||"string",r.mimeType)},generateAsync:function(t,e){return this.generateInternalStream(t).accumulate(e)},generateNodeStream:function(t,e){return(t=t||{}).type||(t.type="nodebuffer"),this.generateInternalStream(t).toNodejsStream(e)}};e.exports=i},{"./compressedObject":2,"./defaults":5,"./generate":9,"./nodejs/NodejsStreamInputAdapter":12,"./nodejsUtils":14,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31,"./utils":32,"./zipObject":35}],16:[function(t,e,r){e.exports=t("stream")},{stream:void 0}],17:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t);for(var e=0;e<this.data.length;e++)t[e]=255&t[e]}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data[this.zero+t]},n.prototype.lastIndexOfSignature=function(t){for(var e=t.charCodeAt(0),r=t.charCodeAt(1),i=t.charCodeAt(2),n=t.charCodeAt(3),s=this.length-4;0<=s;--s)if(this.data[s]===e&&this.data[s+1]===r&&this.data[s+2]===i&&this.data[s+3]===n)return s-this.zero;return-1},n.prototype.readAndCheckSignature=function(t){var e=t.charCodeAt(0),r=t.charCodeAt(1),i=t.charCodeAt(2),n=t.charCodeAt(3),s=this.readData(4);return e===s[0]&&r===s[1]&&i===s[2]&&n===s[3]},n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return[];var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],18:[function(t,e,r){"use strict";var i=t("../utils");function n(t){this.data=t,this.length=t.length,this.index=0,this.zero=0}n.prototype={checkOffset:function(t){this.checkIndex(this.index+t)},checkIndex:function(t){if(this.length<this.zero+t||t<0)throw new Error("End of data reached (data length = "+this.length+", asked index = "+t+"). Corrupted zip ?")},setIndex:function(t){this.checkIndex(t),this.index=t},skip:function(t){this.setIndex(this.index+t)},byteAt:function(t){},readInt:function(t){var e,r=0;for(this.checkOffset(t),e=this.index+t-1;e>=this.index;e--)r=(r<<8)+this.byteAt(e);return this.index+=t,r},readString:function(t){return i.transformTo("string",this.readData(t))},readData:function(t){},lastIndexOfSignature:function(t){},readAndCheckSignature:function(t){},readDate:function(){var t=this.readInt(4);return new Date(Date.UTC(1980+(t>>25&127),(t>>21&15)-1,t>>16&31,t>>11&31,t>>5&63,(31&t)<<1))}},e.exports=n},{"../utils":32}],19:[function(t,e,r){"use strict";var i=t("./Uint8ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./Uint8ArrayReader":21}],20:[function(t,e,r){"use strict";var i=t("./DataReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.byteAt=function(t){return this.data.charCodeAt(this.zero+t)},n.prototype.lastIndexOfSignature=function(t){return this.data.lastIndexOf(t)-this.zero},n.prototype.readAndCheckSignature=function(t){return t===this.readData(4)},n.prototype.readData=function(t){this.checkOffset(t);var e=this.data.slice(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./DataReader":18}],21:[function(t,e,r){"use strict";var i=t("./ArrayReader");function n(t){i.call(this,t)}t("../utils").inherits(n,i),n.prototype.readData=function(t){if(this.checkOffset(t),0===t)return new Uint8Array(0);var e=this.data.subarray(this.zero+this.index,this.zero+this.index+t);return this.index+=t,e},e.exports=n},{"../utils":32,"./ArrayReader":17}],22:[function(t,e,r){"use strict";var i=t("../utils"),n=t("../support"),s=t("./ArrayReader"),a=t("./StringReader"),o=t("./NodeBufferReader"),h=t("./Uint8ArrayReader");e.exports=function(t){var e=i.getTypeOf(t);return i.checkSupport(e),"string"!==e||n.uint8array?"nodebuffer"===e?new o(t):n.uint8array?new h(i.transformTo("uint8array",t)):new s(i.transformTo("array",t)):new a(t)}},{"../support":30,"../utils":32,"./ArrayReader":17,"./NodeBufferReader":19,"./StringReader":20,"./Uint8ArrayReader":21}],23:[function(t,e,r){"use strict";r.LOCAL_FILE_HEADER="PK",r.CENTRAL_FILE_HEADER="PK",r.CENTRAL_DIRECTORY_END="PK",r.ZIP64_CENTRAL_DIRECTORY_LOCATOR="PK",r.ZIP64_CENTRAL_DIRECTORY_END="PK",r.DATA_DESCRIPTOR="PK\b"},{}],24:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../utils");function s(t){i.call(this,"ConvertWorker to "+t),this.destType=t}n.inherits(s,i),s.prototype.processChunk=function(t){this.push({data:n.transformTo(this.destType,t.data),meta:t.meta})},e.exports=s},{"../utils":32,"./GenericWorker":28}],25:[function(t,e,r){"use strict";var i=t("./GenericWorker"),n=t("../crc32");function s(){i.call(this,"Crc32Probe"),this.withStreamInfo("crc32",0)}t("../utils").inherits(s,i),s.prototype.processChunk=function(t){this.streamInfo.crc32=n(t.data,this.streamInfo.crc32||0),this.push(t)},e.exports=s},{"../crc32":4,"../utils":32,"./GenericWorker":28}],26:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataLengthProbe for "+t),this.propName=t,this.withStreamInfo(t,0)}i.inherits(s,n),s.prototype.processChunk=function(t){if(t){var e=this.streamInfo[this.propName]||0;this.streamInfo[this.propName]=e+t.data.length}n.prototype.processChunk.call(this,t)},e.exports=s},{"../utils":32,"./GenericWorker":28}],27:[function(t,e,r){"use strict";var i=t("../utils"),n=t("./GenericWorker");function s(t){n.call(this,"DataWorker");var e=this;this.dataIsReady=!1,this.index=0,this.max=0,this.data=null,this.type="",this._tickScheduled=!1,t.then(function(t){e.dataIsReady=!0,e.data=t,e.max=t&&t.length||0,e.type=i.getTypeOf(t),e.isPaused||e._tickAndRepeat()},function(t){e.error(t)})}i.inherits(s,n),s.prototype.cleanUp=function(){n.prototype.cleanUp.call(this),this.data=null},s.prototype.resume=function(){return!!n.prototype.resume.call(this)&&(!this._tickScheduled&&this.dataIsReady&&(this._tickScheduled=!0,i.delay(this._tickAndRepeat,[],this)),!0)},s.prototype._tickAndRepeat=function(){this._tickScheduled=!1,this.isPaused||this.isFinished||(this._tick(),this.isFinished||(i.delay(this._tickAndRepeat,[],this),this._tickScheduled=!0))},s.prototype._tick=function(){if(this.isPaused||this.isFinished)return!1;var t=null,e=Math.min(this.max,this.index+16384);if(this.index>=this.max)return this.end();switch(this.type){case"string":t=this.data.substring(this.index,e);break;case"uint8array":t=this.data.subarray(this.index,e);break;case"array":case"nodebuffer":t=this.data.slice(this.index,e)}return this.index=e,this.push({data:t,meta:{percent:this.max?this.index/this.max*100:0}})},e.exports=s},{"../utils":32,"./GenericWorker":28}],28:[function(t,e,r){"use strict";function i(t){this.name=t||"default",this.streamInfo={},this.generatedError=null,this.extraStreamInfo={},this.isPaused=!0,this.isFinished=!1,this.isLocked=!1,this._listeners={data:[],end:[],error:[]},this.previous=null}i.prototype={push:function(t){this.emit("data",t)},end:function(){if(this.isFinished)return!1;this.flush();try{this.emit("end"),this.cleanUp(),this.isFinished=!0}catch(t){this.emit("error",t)}return!0},error:function(t){return!this.isFinished&&(this.isPaused?this.generatedError=t:(this.isFinished=!0,this.emit("error",t),this.previous&&this.previous.error(t),this.cleanUp()),!0)},on:function(t,e){return this._listeners[t].push(e),this},cleanUp:function(){this.streamInfo=this.generatedError=this.extraStreamInfo=null,this._listeners=[]},emit:function(t,e){if(this._listeners[t])for(var r=0;r<this._listeners[t].length;r++)this._listeners[t][r].call(this,e)},pipe:function(t){return t.registerPrevious(this)},registerPrevious:function(t){if(this.isLocked)throw new Error("The stream '"+this+"' has already been used.");this.streamInfo=t.streamInfo,this.mergeStreamInfo(),this.previous=t;var e=this;return t.on("data",function(t){e.processChunk(t)}),t.on("end",function(){e.end()}),t.on("error",function(t){e.error(t)}),this},pause:function(){return!this.isPaused&&!this.isFinished&&(this.isPaused=!0,this.previous&&this.previous.pause(),!0)},resume:function(){if(!this.isPaused||this.isFinished)return!1;var t=this.isPaused=!1;return this.generatedError&&(this.error(this.generatedError),t=!0),this.previous&&this.previous.resume(),!t},flush:function(){},processChunk:function(t){this.push(t)},withStreamInfo:function(t,e){return this.extraStreamInfo[t]=e,this.mergeStreamInfo(),this},mergeStreamInfo:function(){for(var t in this.extraStreamInfo)this.extraStreamInfo.hasOwnProperty(t)&&(this.streamInfo[t]=this.extraStreamInfo[t])},lock:function(){if(this.isLocked)throw new Error("The stream '"+this+"' has already been used.");this.isLocked=!0,this.previous&&this.previous.lock()},toString:function(){var t="Worker "+this.name;return this.previous?this.previous+" -> "+t:t}},e.exports=i},{}],29:[function(t,e,r){"use strict";var h=t("../utils"),n=t("./ConvertWorker"),s=t("./GenericWorker"),u=t("../base64"),i=t("../support"),a=t("../external"),o=null;if(i.nodestream)try{o=t("../nodejs/NodejsStreamOutputAdapter")}catch(t){}function l(t,o){return new a.Promise(function(e,r){var i=[],n=t._internalType,s=t._outputType,a=t._mimeType;t.on("data",function(t,e){i.push(t),o&&o(e)}).on("error",function(t){i=[],r(t)}).on("end",function(){try{var t=function(t,e,r){switch(t){case"blob":return h.newBlob(h.transformTo("arraybuffer",e),r);case"base64":return u.encode(e);default:return h.transformTo(t,e)}}(s,function(t,e){var r,i=0,n=null,s=0;for(r=0;r<e.length;r++)s+=e[r].length;switch(t){case"string":return e.join("");case"array":return Array.prototype.concat.apply([],e);case"uint8array":for(n=new Uint8Array(s),r=0;r<e.length;r++)n.set(e[r],i),i+=e[r].length;return n;case"nodebuffer":return Buffer.concat(e);default:throw new Error("concat : unsupported type '"+t+"'")}}(n,i),a);e(t)}catch(t){r(t)}i=[]}).resume()})}function f(t,e,r){var i=e;switch(e){case"blob":case"arraybuffer":i="uint8array";break;case"base64":i="string"}try{this._internalType=i,this._outputType=e,this._mimeType=r,h.checkSupport(i),this._worker=t.pipe(new n(i)),t.lock()}catch(t){this._worker=new s("error"),this._worker.error(t)}}f.prototype={accumulate:function(t){return l(this,t)},on:function(t,e){var r=this;return"data"===t?this._worker.on(t,function(t){e.call(r,t.data,t.meta)}):this._worker.on(t,function(){h.delay(e,arguments,r)}),this},resume:function(){return h.delay(this._worker.resume,[],this._worker),this},pause:function(){return this._worker.pause(),this},toNodejsStream:function(t){if(h.checkSupport("nodestream"),"nodebuffer"!==this._outputType)throw new Error(this._outputType+" is not supported by this method");return new o(this,{objectMode:"nodebuffer"!==this._outputType},t)}},e.exports=f},{"../base64":1,"../external":6,"../nodejs/NodejsStreamOutputAdapter":13,"../support":30,"../utils":32,"./ConvertWorker":24,"./GenericWorker":28}],30:[function(t,e,r){"use strict";if(r.base64=!0,r.array=!0,r.string=!0,r.arraybuffer="undefined"!=typeof ArrayBuffer&&"undefined"!=typeof Uint8Array,r.nodebuffer="undefined"!=typeof Buffer,r.uint8array="undefined"!=typeof Uint8Array,"undefined"==typeof ArrayBuffer)r.blob=!1;else{var i=new ArrayBuffer(0);try{r.blob=0===new Blob([i],{type:"application/zip"}).size}catch(t){try{var n=new(self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder);n.append(i),r.blob=0===n.getBlob("application/zip").size}catch(t){r.blob=!1}}}try{r.nodestream=!!t("readable-stream").Readable}catch(t){r.nodestream=!1}},{"readable-stream":16}],31:[function(t,e,s){"use strict";for(var o=t("./utils"),h=t("./support"),r=t("./nodejsUtils"),i=t("./stream/GenericWorker"),u=new Array(256),n=0;n<256;n++)u[n]=252<=n?6:248<=n?5:240<=n?4:224<=n?3:192<=n?2:1;u[254]=u[254]=1;function a(){i.call(this,"utf-8 decode"),this.leftOver=null}function l(){i.call(this,"utf-8 encode")}s.utf8encode=function(t){return h.nodebuffer?r.newBufferFrom(t,"utf-8"):function(t){var e,r,i,n,s,a=t.length,o=0;for(n=0;n<a;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),o+=r<128?1:r<2048?2:r<65536?3:4;for(e=h.uint8array?new Uint8Array(o):new Array(o),n=s=0;s<o;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),r<128?e[s++]=r:(r<2048?e[s++]=192|r>>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e}(t)},s.utf8decode=function(t){return h.nodebuffer?o.transformTo("nodebuffer",t).toString("utf-8"):function(t){var e,r,i,n,s=t.length,a=new Array(2*s);for(e=r=0;e<s;)if((i=t[e++])<128)a[r++]=i;else if(4<(n=u[i]))a[r++]=65533,e+=n-1;else{for(i&=2===n?31:3===n?15:7;1<n&&e<s;)i=i<<6|63&t[e++],n--;1<n?a[r++]=65533:i<65536?a[r++]=i:(i-=65536,a[r++]=55296|i>>10&1023,a[r++]=56320|1023&i)}return a.length!==r&&(a.subarray?a=a.subarray(0,r):a.length=r),o.applyFromCharCode(a)}(t=o.transformTo(h.uint8array?"uint8array":"array",t))},o.inherits(a,i),a.prototype.processChunk=function(t){var e=o.transformTo(h.uint8array?"uint8array":"array",t.data);if(this.leftOver&&this.leftOver.length){if(h.uint8array){var r=e;(e=new Uint8Array(r.length+this.leftOver.length)).set(this.leftOver,0),e.set(r,this.leftOver.length)}else e=this.leftOver.concat(e);this.leftOver=null}var i=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}(e),n=e;i!==e.length&&(h.uint8array?(n=e.subarray(0,i),this.leftOver=e.subarray(i,e.length)):(n=e.slice(0,i),this.leftOver=e.slice(i,e.length))),this.push({data:s.utf8decode(n),meta:t.meta})},a.prototype.flush=function(){this.leftOver&&this.leftOver.length&&(this.push({data:s.utf8decode(this.leftOver),meta:{}}),this.leftOver=null)},s.Utf8DecodeWorker=a,o.inherits(l,i),l.prototype.processChunk=function(t){this.push({data:s.utf8encode(t.data),meta:t.meta})},s.Utf8EncodeWorker=l},{"./nodejsUtils":14,"./stream/GenericWorker":28,"./support":30,"./utils":32}],32:[function(t,e,a){"use strict";var o=t("./support"),h=t("./base64"),r=t("./nodejsUtils"),i=t("set-immediate-shim"),u=t("./external");function n(t){return t}function l(t,e){for(var r=0;r<t.length;++r)e[r]=255&t.charCodeAt(r);return e}a.newBlob=function(e,r){a.checkSupport("blob");try{return new Blob([e],{type:r})}catch(t){try{var i=new(self.BlobBuilder||self.WebKitBlobBuilder||self.MozBlobBuilder||self.MSBlobBuilder);return i.append(e),i.getBlob(r)}catch(t){throw new Error("Bug : can't construct the Blob.")}}};var s={stringifyByChunk:function(t,e,r){var i=[],n=0,s=t.length;if(s<=r)return String.fromCharCode.apply(null,t);for(;n<s;)"array"===e||"nodebuffer"===e?i.push(String.fromCharCode.apply(null,t.slice(n,Math.min(n+r,s)))):i.push(String.fromCharCode.apply(null,t.subarray(n,Math.min(n+r,s)))),n+=r;return i.join("")},stringifyByChar:function(t){for(var e="",r=0;r<t.length;r++)e+=String.fromCharCode(t[r]);return e},applyCanBeUsed:{uint8array:function(){try{return o.uint8array&&1===String.fromCharCode.apply(null,new Uint8Array(1)).length}catch(t){return!1}}(),nodebuffer:function(){try{return o.nodebuffer&&1===String.fromCharCode.apply(null,r.allocBuffer(1)).length}catch(t){return!1}}()}};function f(t){var e=65536,r=a.getTypeOf(t),i=!0;if("uint8array"===r?i=s.applyCanBeUsed.uint8array:"nodebuffer"===r&&(i=s.applyCanBeUsed.nodebuffer),i)for(;1<e;)try{return s.stringifyByChunk(t,r,e)}catch(t){e=Math.floor(e/2)}return s.stringifyByChar(t)}function d(t,e){for(var r=0;r<t.length;r++)e[r]=t[r];return e}a.applyFromCharCode=f;var c={};c.string={string:n,array:function(t){return l(t,new Array(t.length))},arraybuffer:function(t){return c.string.uint8array(t).buffer},uint8array:function(t){return l(t,new Uint8Array(t.length))},nodebuffer:function(t){return l(t,r.allocBuffer(t.length))}},c.array={string:f,array:n,arraybuffer:function(t){return new Uint8Array(t).buffer},uint8array:function(t){return new Uint8Array(t)},nodebuffer:function(t){return r.newBufferFrom(t)}},c.arraybuffer={string:function(t){return f(new Uint8Array(t))},array:function(t){return d(new Uint8Array(t),new Array(t.byteLength))},arraybuffer:n,uint8array:function(t){return new Uint8Array(t)},nodebuffer:function(t){return r.newBufferFrom(new Uint8Array(t))}},c.uint8array={string:f,array:function(t){return d(t,new Array(t.length))},arraybuffer:function(t){return t.buffer},uint8array:n,nodebuffer:function(t){return r.newBufferFrom(t)}},c.nodebuffer={string:f,array:function(t){return d(t,new Array(t.length))},arraybuffer:function(t){return c.nodebuffer.uint8array(t).buffer},uint8array:function(t){return d(t,new Uint8Array(t.length))},nodebuffer:n},a.transformTo=function(t,e){if(e=e||"",!t)return e;a.checkSupport(t);var r=a.getTypeOf(e);return c[r][t](e)},a.getTypeOf=function(t){return"string"==typeof t?"string":"[object Array]"===Object.prototype.toString.call(t)?"array":o.nodebuffer&&r.isBuffer(t)?"nodebuffer":o.uint8array&&t instanceof Uint8Array?"uint8array":o.arraybuffer&&t instanceof ArrayBuffer?"arraybuffer":void 0},a.checkSupport=function(t){if(!o[t.toLowerCase()])throw new Error(t+" is not supported by this platform")},a.MAX_VALUE_16BITS=65535,a.MAX_VALUE_32BITS=-1,a.pretty=function(t){var e,r,i="";for(r=0;r<(t||"").length;r++)i+="\\x"+((e=t.charCodeAt(r))<16?"0":"")+e.toString(16).toUpperCase();return i},a.delay=function(t,e,r){i(function(){t.apply(r||null,e||[])})},a.inherits=function(t,e){function r(){}r.prototype=e.prototype,t.prototype=new r},a.extend=function(){var t,e,r={};for(t=0;t<arguments.length;t++)for(e in arguments[t])arguments[t].hasOwnProperty(e)&&void 0===r[e]&&(r[e]=arguments[t][e]);return r},a.prepareContent=function(r,t,i,n,s){return u.Promise.resolve(t).then(function(i){return o.blob&&(i instanceof Blob||-1!==["[object File]","[object Blob]"].indexOf(Object.prototype.toString.call(i)))&&"undefined"!=typeof FileReader?new u.Promise(function(e,r){var t=new FileReader;t.onload=function(t){e(t.target.result)},t.onerror=function(t){r(t.target.error)},t.readAsArrayBuffer(i)}):i}).then(function(t){var e=a.getTypeOf(t);return e?("arraybuffer"===e?t=a.transformTo("uint8array",t):"string"===e&&(s?t=h.decode(t):i&&!0!==n&&(t=function(t){return l(t,o.uint8array?new Uint8Array(t.length):new Array(t.length))}(t))),t):u.Promise.reject(new Error("Can't read the data of '"+r+"'. Is it in a supported JavaScript type (String, Blob, ArrayBuffer, etc) ?"))})}},{"./base64":1,"./external":6,"./nodejsUtils":14,"./support":30,"set-immediate-shim":54}],33:[function(t,e,r){"use strict";var i=t("./reader/readerFor"),n=t("./utils"),s=t("./signature"),a=t("./zipEntry"),o=(t("./utf8"),t("./support"));function h(t){this.files=[],this.loadOptions=t}h.prototype={checkSignature:function(t){if(!this.reader.readAndCheckSignature(t)){this.reader.index-=4;var e=this.reader.readString(4);throw new Error("Corrupted zip or bug: unexpected signature ("+n.pretty(e)+", expected "+n.pretty(t)+")")}},isSignature:function(t,e){var r=this.reader.index;this.reader.setIndex(t);var i=this.reader.readString(4)===e;return this.reader.setIndex(r),i},readBlockEndOfCentral:function(){this.diskNumber=this.reader.readInt(2),this.diskWithCentralDirStart=this.reader.readInt(2),this.centralDirRecordsOnThisDisk=this.reader.readInt(2),this.centralDirRecords=this.reader.readInt(2),this.centralDirSize=this.reader.readInt(4),this.centralDirOffset=this.reader.readInt(4),this.zipCommentLength=this.reader.readInt(2);var t=this.reader.readData(this.zipCommentLength),e=o.uint8array?"uint8array":"array",r=n.transformTo(e,t);this.zipComment=this.loadOptions.decodeFileName(r)},readBlockZip64EndOfCentral:function(){this.zip64EndOfCentralSize=this.reader.readInt(8),this.reader.skip(4),this.diskNumber=this.reader.readInt(4),this.diskWithCentralDirStart=this.reader.readInt(4),this.centralDirRecordsOnThisDisk=this.reader.readInt(8),this.centralDirRecords=this.reader.readInt(8),this.centralDirSize=this.reader.readInt(8),this.centralDirOffset=this.reader.readInt(8),this.zip64ExtensibleData={};for(var t,e,r,i=this.zip64EndOfCentralSize-44;0<i;)t=this.reader.readInt(2),e=this.reader.readInt(4),r=this.reader.readData(e),this.zip64ExtensibleData[t]={id:t,length:e,value:r}},readBlockZip64EndOfCentralLocator:function(){if(this.diskWithZip64CentralDirStart=this.reader.readInt(4),this.relativeOffsetEndOfZip64CentralDir=this.reader.readInt(8),this.disksCount=this.reader.readInt(4),1<this.disksCount)throw new Error("Multi-volumes zip are not supported")},readLocalFiles:function(){var t,e;for(t=0;t<this.files.length;t++)e=this.files[t],this.reader.setIndex(e.localHeaderOffset),this.checkSignature(s.LOCAL_FILE_HEADER),e.readLocalPart(this.reader),e.handleUTF8(),e.processAttributes()},readCentralDir:function(){var t;for(this.reader.setIndex(this.centralDirOffset);this.reader.readAndCheckSignature(s.CENTRAL_FILE_HEADER);)(t=new a({zip64:this.zip64},this.loadOptions)).readCentralPart(this.reader),this.files.push(t);if(this.centralDirRecords!==this.files.length&&0!==this.centralDirRecords&&0===this.files.length)throw new Error("Corrupted zip or bug: expected "+this.centralDirRecords+" records in central dir, got "+this.files.length)},readEndOfCentral:function(){var t=this.reader.lastIndexOfSignature(s.CENTRAL_DIRECTORY_END);if(t<0)throw!this.isSignature(0,s.LOCAL_FILE_HEADER)?new Error("Can't find end of central directory : is this a zip file ? If it is, see https://stuk.github.io/jszip/documentation/howto/read_zip.html"):new Error("Corrupted zip: can't find end of central directory");this.reader.setIndex(t);var e=t;if(this.checkSignature(s.CENTRAL_DIRECTORY_END),this.readBlockEndOfCentral(),this.diskNumber===n.MAX_VALUE_16BITS||this.diskWithCentralDirStart===n.MAX_VALUE_16BITS||this.centralDirRecordsOnThisDisk===n.MAX_VALUE_16BITS||this.centralDirRecords===n.MAX_VALUE_16BITS||this.centralDirSize===n.MAX_VALUE_32BITS||this.centralDirOffset===n.MAX_VALUE_32BITS){if(this.zip64=!0,(t=this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR))<0)throw new Error("Corrupted zip: can't find the ZIP64 end of central directory locator");if(this.reader.setIndex(t),this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_LOCATOR),this.readBlockZip64EndOfCentralLocator(),!this.isSignature(this.relativeOffsetEndOfZip64CentralDir,s.ZIP64_CENTRAL_DIRECTORY_END)&&(this.relativeOffsetEndOfZip64CentralDir=this.reader.lastIndexOfSignature(s.ZIP64_CENTRAL_DIRECTORY_END),this.relativeOffsetEndOfZip64CentralDir<0))throw new Error("Corrupted zip: can't find the ZIP64 end of central directory");this.reader.setIndex(this.relativeOffsetEndOfZip64CentralDir),this.checkSignature(s.ZIP64_CENTRAL_DIRECTORY_END),this.readBlockZip64EndOfCentral()}var r=this.centralDirOffset+this.centralDirSize;this.zip64&&(r+=20,r+=12+this.zip64EndOfCentralSize);var i=e-r;if(0<i)this.isSignature(e,s.CENTRAL_FILE_HEADER)||(this.reader.zero=i);else if(i<0)throw new Error("Corrupted zip: missing "+Math.abs(i)+" bytes.")},prepareReader:function(t){this.reader=i(t)},load:function(t){this.prepareReader(t),this.readEndOfCentral(),this.readCentralDir(),this.readLocalFiles()}},e.exports=h},{"./reader/readerFor":22,"./signature":23,"./support":30,"./utf8":31,"./utils":32,"./zipEntry":34}],34:[function(t,e,r){"use strict";var i=t("./reader/readerFor"),s=t("./utils"),n=t("./compressedObject"),a=t("./crc32"),o=t("./utf8"),h=t("./compressions"),u=t("./support");function l(t,e){this.options=t,this.loadOptions=e}l.prototype={isEncrypted:function(){return 1==(1&this.bitFlag)},useUTF8:function(){return 2048==(2048&this.bitFlag)},readLocalPart:function(t){var e,r;if(t.skip(22),this.fileNameLength=t.readInt(2),r=t.readInt(2),this.fileName=t.readData(this.fileNameLength),t.skip(r),-1===this.compressedSize||-1===this.uncompressedSize)throw new Error("Bug or corrupted zip : didn't get enough information from the central directory (compressedSize === -1 || uncompressedSize === -1)");if(null===(e=function(t){for(var e in h)if(h.hasOwnProperty(e)&&h[e].magic===t)return h[e];return null}(this.compressionMethod)))throw new Error("Corrupted zip : compression "+s.pretty(this.compressionMethod)+" unknown (inner file : "+s.transformTo("string",this.fileName)+")");this.decompressed=new n(this.compressedSize,this.uncompressedSize,this.crc32,e,t.readData(this.compressedSize))},readCentralPart:function(t){this.versionMadeBy=t.readInt(2),t.skip(2),this.bitFlag=t.readInt(2),this.compressionMethod=t.readString(2),this.date=t.readDate(),this.crc32=t.readInt(4),this.compressedSize=t.readInt(4),this.uncompressedSize=t.readInt(4);var e=t.readInt(2);if(this.extraFieldsLength=t.readInt(2),this.fileCommentLength=t.readInt(2),this.diskNumberStart=t.readInt(2),this.internalFileAttributes=t.readInt(2),this.externalFileAttributes=t.readInt(4),this.localHeaderOffset=t.readInt(4),this.isEncrypted())throw new Error("Encrypted zip are not supported");t.skip(e),this.readExtraFields(t),this.parseZIP64ExtraField(t),this.fileComment=t.readData(this.fileCommentLength)},processAttributes:function(){this.unixPermissions=null,this.dosPermissions=null;var t=this.versionMadeBy>>8;this.dir=!!(16&this.externalFileAttributes),0==t&&(this.dosPermissions=63&this.externalFileAttributes),3==t&&(this.unixPermissions=this.externalFileAttributes>>16&65535),this.dir||"/"!==this.fileNameStr.slice(-1)||(this.dir=!0)},parseZIP64ExtraField:function(t){if(this.extraFields[1]){var e=i(this.extraFields[1].value);this.uncompressedSize===s.MAX_VALUE_32BITS&&(this.uncompressedSize=e.readInt(8)),this.compressedSize===s.MAX_VALUE_32BITS&&(this.compressedSize=e.readInt(8)),this.localHeaderOffset===s.MAX_VALUE_32BITS&&(this.localHeaderOffset=e.readInt(8)),this.diskNumberStart===s.MAX_VALUE_32BITS&&(this.diskNumberStart=e.readInt(4))}},readExtraFields:function(t){var e,r,i,n=t.index+this.extraFieldsLength;for(this.extraFields||(this.extraFields={});t.index<n;)e=t.readInt(2),r=t.readInt(2),i=t.readData(r),this.extraFields[e]={id:e,length:r,value:i}},handleUTF8:function(){var t=u.uint8array?"uint8array":"array";if(this.useUTF8())this.fileNameStr=o.utf8decode(this.fileName),this.fileCommentStr=o.utf8decode(this.fileComment);else{var e=this.findExtraFieldUnicodePath();if(null!==e)this.fileNameStr=e;else{var r=s.transformTo(t,this.fileName);this.fileNameStr=this.loadOptions.decodeFileName(r)}var i=this.findExtraFieldUnicodeComment();if(null!==i)this.fileCommentStr=i;else{var n=s.transformTo(t,this.fileComment);this.fileCommentStr=this.loadOptions.decodeFileName(n)}}},findExtraFieldUnicodePath:function(){var t=this.extraFields[28789];if(t){var e=i(t.value);return 1!==e.readInt(1)?null:a(this.fileName)!==e.readInt(4)?null:o.utf8decode(e.readData(t.length-5))}return null},findExtraFieldUnicodeComment:function(){var t=this.extraFields[25461];if(t){var e=i(t.value);return 1!==e.readInt(1)?null:a(this.fileComment)!==e.readInt(4)?null:o.utf8decode(e.readData(t.length-5))}return null}},e.exports=l},{"./compressedObject":2,"./compressions":3,"./crc32":4,"./reader/readerFor":22,"./support":30,"./utf8":31,"./utils":32}],35:[function(t,e,r){"use strict";function i(t,e,r){this.name=t,this.dir=r.dir,this.date=r.date,this.comment=r.comment,this.unixPermissions=r.unixPermissions,this.dosPermissions=r.dosPermissions,this._data=e,this._dataBinary=r.binary,this.options={compression:r.compression,compressionOptions:r.compressionOptions}}var s=t("./stream/StreamHelper"),n=t("./stream/DataWorker"),a=t("./utf8"),o=t("./compressedObject"),h=t("./stream/GenericWorker");i.prototype={internalStream:function(t){var e=null,r="string";try{if(!t)throw new Error("No output type specified.");var i="string"===(r=t.toLowerCase())||"text"===r;"binarystring"!==r&&"text"!==r||(r="string"),e=this._decompressWorker();var n=!this._dataBinary;n&&!i&&(e=e.pipe(new a.Utf8EncodeWorker)),!n&&i&&(e=e.pipe(new a.Utf8DecodeWorker))}catch(t){(e=new h("error")).error(t)}return new s(e,r,"")},async:function(t,e){return this.internalStream(t).accumulate(e)},nodeStream:function(t,e){return this.internalStream(t||"nodebuffer").toNodejsStream(e)},_compressWorker:function(t,e){if(this._data instanceof o&&this._data.compression.magic===t.magic)return this._data.getCompressedWorker();var r=this._decompressWorker();return this._dataBinary||(r=r.pipe(new a.Utf8EncodeWorker)),o.createWorkerFrom(r,t,e)},_decompressWorker:function(){return this._data instanceof o?this._data.getContentWorker():this._data instanceof h?this._data:new n(this._data)}};for(var u=["asText","asBinary","asNodeBuffer","asUint8Array","asArrayBuffer"],l=function(){throw new Error("This method has been removed in JSZip 3.0, please check the upgrade guide.")},f=0;f<u.length;f++)i.prototype[u[f]]=l;e.exports=i},{"./compressedObject":2,"./stream/DataWorker":27,"./stream/GenericWorker":28,"./stream/StreamHelper":29,"./utf8":31}],36:[function(t,l,e){(function(e){"use strict";var r,i,t=e.MutationObserver||e.WebKitMutationObserver;if(t){var n=0,s=new t(u),a=e.document.createTextNode("");s.observe(a,{characterData:!0}),r=function(){a.data=n=++n%2}}else if(e.setImmediate||void 0===e.MessageChannel)r="document"in e&&"onreadystatechange"in e.document.createElement("script")?function(){var t=e.document.createElement("script");t.onreadystatechange=function(){u(),t.onreadystatechange=null,t.parentNode.removeChild(t),t=null},e.document.documentElement.appendChild(t)}:function(){setTimeout(u,0)};else{var o=new e.MessageChannel;o.port1.onmessage=u,r=function(){o.port2.postMessage(0)}}var h=[];function u(){var t,e;i=!0;for(var r=h.length;r;){for(e=h,h=[],t=-1;++t<r;)e[t]();r=h.length}i=!1}l.exports=function(t){1!==h.push(t)||i||r()}}).call(this,"undefined"!=typeof global?global:"undefined"!=typeof self?self:"undefined"!=typeof window?window:{})},{}],37:[function(t,e,r){"use strict";var n=t("immediate");function u(){}var l={},s=["REJECTED"],a=["FULFILLED"],i=["PENDING"];function o(t){if("function"!=typeof t)throw new TypeError("resolver must be a function");this.state=i,this.queue=[],this.outcome=void 0,t!==u&&c(this,t)}function h(t,e,r){this.promise=t,"function"==typeof e&&(this.onFulfilled=e,this.callFulfilled=this.otherCallFulfilled),"function"==typeof r&&(this.onRejected=r,this.callRejected=this.otherCallRejected)}function f(e,r,i){n(function(){var t;try{t=r(i)}catch(t){return l.reject(e,t)}t===e?l.reject(e,new TypeError("Cannot resolve promise with itself")):l.resolve(e,t)})}function d(t){var e=t&&t.then;if(t&&("object"==typeof t||"function"==typeof t)&&"function"==typeof e)return function(){e.apply(t,arguments)}}function c(e,t){var r=!1;function i(t){r||(r=!0,l.reject(e,t))}function n(t){r||(r=!0,l.resolve(e,t))}var s=p(function(){t(n,i)});"error"===s.status&&i(s.value)}function p(t,e){var r={};try{r.value=t(e),r.status="success"}catch(t){r.status="error",r.value=t}return r}(e.exports=o).prototype.finally=function(e){if("function"!=typeof e)return this;var r=this.constructor;return this.then(function(t){return r.resolve(e()).then(function(){return t})},function(t){return r.resolve(e()).then(function(){throw t})})},o.prototype.catch=function(t){return this.then(null,t)},o.prototype.then=function(t,e){if("function"!=typeof t&&this.state===a||"function"!=typeof e&&this.state===s)return this;var r=new this.constructor(u);this.state!==i?f(r,this.state===a?t:e,this.outcome):this.queue.push(new h(r,t,e));return r},h.prototype.callFulfilled=function(t){l.resolve(this.promise,t)},h.prototype.otherCallFulfilled=function(t){f(this.promise,this.onFulfilled,t)},h.prototype.callRejected=function(t){l.reject(this.promise,t)},h.prototype.otherCallRejected=function(t){f(this.promise,this.onRejected,t)},l.resolve=function(t,e){var r=p(d,e);if("error"===r.status)return l.reject(t,r.value);var i=r.value;if(i)c(t,i);else{t.state=a,t.outcome=e;for(var n=-1,s=t.queue.length;++n<s;)t.queue[n].callFulfilled(e)}return t},l.reject=function(t,e){t.state=s,t.outcome=e;for(var r=-1,i=t.queue.length;++r<i;)t.queue[r].callRejected(e);return t},o.resolve=function(t){if(t instanceof this)return t;return l.resolve(new this(u),t)},o.reject=function(t){var e=new this(u);return l.reject(e,t)},o.all=function(t){var r=this;if("[object Array]"!==Object.prototype.toString.call(t))return this.reject(new TypeError("must be an array"));var i=t.length,n=!1;if(!i)return this.resolve([]);var s=new Array(i),a=0,e=-1,o=new this(u);for(;++e<i;)h(t[e],e);return o;function h(t,e){r.resolve(t).then(function(t){s[e]=t,++a!==i||n||(n=!0,l.resolve(o,s))},function(t){n||(n=!0,l.reject(o,t))})}},o.race=function(t){var e=this;if("[object Array]"!==Object.prototype.toString.call(t))return this.reject(new TypeError("must be an array"));var r=t.length,i=!1;if(!r)return this.resolve([]);var n=-1,s=new this(u);for(;++n<r;)a=t[n],e.resolve(a).then(function(t){i||(i=!0,l.resolve(s,t))},function(t){i||(i=!0,l.reject(s,t))});var a;return s}},{immediate:36}],38:[function(t,e,r){"use strict";var i={};(0,t("./lib/utils/common").assign)(i,t("./lib/deflate"),t("./lib/inflate"),t("./lib/zlib/constants")),e.exports=i},{"./lib/deflate":39,"./lib/inflate":40,"./lib/utils/common":41,"./lib/zlib/constants":44}],39:[function(t,e,r){"use strict";var a=t("./zlib/deflate"),o=t("./utils/common"),h=t("./utils/strings"),n=t("./zlib/messages"),s=t("./zlib/zstream"),u=Object.prototype.toString,l=0,f=-1,d=0,c=8;function p(t){if(!(this instanceof p))return new p(t);this.options=o.assign({level:f,method:c,chunkSize:16384,windowBits:15,memLevel:8,strategy:d,to:""},t||{});var e=this.options;e.raw&&0<e.windowBits?e.windowBits=-e.windowBits:e.gzip&&0<e.windowBits&&e.windowBits<16&&(e.windowBits+=16),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new s,this.strm.avail_out=0;var r=a.deflateInit2(this.strm,e.level,e.method,e.windowBits,e.memLevel,e.strategy);if(r!==l)throw new Error(n[r]);if(e.header&&a.deflateSetHeader(this.strm,e.header),e.dictionary){var i;if(i="string"==typeof e.dictionary?h.string2buf(e.dictionary):"[object ArrayBuffer]"===u.call(e.dictionary)?new Uint8Array(e.dictionary):e.dictionary,(r=a.deflateSetDictionary(this.strm,i))!==l)throw new Error(n[r]);this._dict_set=!0}}function i(t,e){var r=new p(e);if(r.push(t,!0),r.err)throw r.msg||n[r.err];return r.result}p.prototype.push=function(t,e){var r,i,n=this.strm,s=this.options.chunkSize;if(this.ended)return!1;i=e===~~e?e:!0===e?4:0,"string"==typeof t?n.input=h.string2buf(t):"[object ArrayBuffer]"===u.call(t)?n.input=new Uint8Array(t):n.input=t,n.next_in=0,n.avail_in=n.input.length;do{if(0===n.avail_out&&(n.output=new o.Buf8(s),n.next_out=0,n.avail_out=s),1!==(r=a.deflate(n,i))&&r!==l)return this.onEnd(r),!(this.ended=!0);0!==n.avail_out&&(0!==n.avail_in||4!==i&&2!==i)||("string"===this.options.to?this.onData(h.buf2binstring(o.shrinkBuf(n.output,n.next_out))):this.onData(o.shrinkBuf(n.output,n.next_out)))}while((0<n.avail_in||0===n.avail_out)&&1!==r);return 4===i?(r=a.deflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===l):2!==i||(this.onEnd(l),!(n.avail_out=0))},p.prototype.onData=function(t){this.chunks.push(t)},p.prototype.onEnd=function(t){t===l&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=o.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},r.Deflate=p,r.deflate=i,r.deflateRaw=function(t,e){return(e=e||{}).raw=!0,i(t,e)},r.gzip=function(t,e){return(e=e||{}).gzip=!0,i(t,e)}},{"./utils/common":41,"./utils/strings":42,"./zlib/deflate":46,"./zlib/messages":51,"./zlib/zstream":53}],40:[function(t,e,r){"use strict";var d=t("./zlib/inflate"),c=t("./utils/common"),p=t("./utils/strings"),m=t("./zlib/constants"),i=t("./zlib/messages"),n=t("./zlib/zstream"),s=t("./zlib/gzheader"),_=Object.prototype.toString;function a(t){if(!(this instanceof a))return new a(t);this.options=c.assign({chunkSize:16384,windowBits:0,to:""},t||{});var e=this.options;e.raw&&0<=e.windowBits&&e.windowBits<16&&(e.windowBits=-e.windowBits,0===e.windowBits&&(e.windowBits=-15)),!(0<=e.windowBits&&e.windowBits<16)||t&&t.windowBits||(e.windowBits+=32),15<e.windowBits&&e.windowBits<48&&0==(15&e.windowBits)&&(e.windowBits|=15),this.err=0,this.msg="",this.ended=!1,this.chunks=[],this.strm=new n,this.strm.avail_out=0;var r=d.inflateInit2(this.strm,e.windowBits);if(r!==m.Z_OK)throw new Error(i[r]);this.header=new s,d.inflateGetHeader(this.strm,this.header)}function o(t,e){var r=new a(e);if(r.push(t,!0),r.err)throw r.msg||i[r.err];return r.result}a.prototype.push=function(t,e){var r,i,n,s,a,o,h=this.strm,u=this.options.chunkSize,l=this.options.dictionary,f=!1;if(this.ended)return!1;i=e===~~e?e:!0===e?m.Z_FINISH:m.Z_NO_FLUSH,"string"==typeof t?h.input=p.binstring2buf(t):"[object ArrayBuffer]"===_.call(t)?h.input=new Uint8Array(t):h.input=t,h.next_in=0,h.avail_in=h.input.length;do{if(0===h.avail_out&&(h.output=new c.Buf8(u),h.next_out=0,h.avail_out=u),(r=d.inflate(h,m.Z_NO_FLUSH))===m.Z_NEED_DICT&&l&&(o="string"==typeof l?p.string2buf(l):"[object ArrayBuffer]"===_.call(l)?new Uint8Array(l):l,r=d.inflateSetDictionary(this.strm,o)),r===m.Z_BUF_ERROR&&!0===f&&(r=m.Z_OK,f=!1),r!==m.Z_STREAM_END&&r!==m.Z_OK)return this.onEnd(r),!(this.ended=!0);h.next_out&&(0!==h.avail_out&&r!==m.Z_STREAM_END&&(0!==h.avail_in||i!==m.Z_FINISH&&i!==m.Z_SYNC_FLUSH)||("string"===this.options.to?(n=p.utf8border(h.output,h.next_out),s=h.next_out-n,a=p.buf2string(h.output,n),h.next_out=s,h.avail_out=u-s,s&&c.arraySet(h.output,h.output,n,s,0),this.onData(a)):this.onData(c.shrinkBuf(h.output,h.next_out)))),0===h.avail_in&&0===h.avail_out&&(f=!0)}while((0<h.avail_in||0===h.avail_out)&&r!==m.Z_STREAM_END);return r===m.Z_STREAM_END&&(i=m.Z_FINISH),i===m.Z_FINISH?(r=d.inflateEnd(this.strm),this.onEnd(r),this.ended=!0,r===m.Z_OK):i!==m.Z_SYNC_FLUSH||(this.onEnd(m.Z_OK),!(h.avail_out=0))},a.prototype.onData=function(t){this.chunks.push(t)},a.prototype.onEnd=function(t){t===m.Z_OK&&("string"===this.options.to?this.result=this.chunks.join(""):this.result=c.flattenChunks(this.chunks)),this.chunks=[],this.err=t,this.msg=this.strm.msg},r.Inflate=a,r.inflate=o,r.inflateRaw=function(t,e){return(e=e||{}).raw=!0,o(t,e)},r.ungzip=o},{"./utils/common":41,"./utils/strings":42,"./zlib/constants":44,"./zlib/gzheader":47,"./zlib/inflate":49,"./zlib/messages":51,"./zlib/zstream":53}],41:[function(t,e,r){"use strict";var i="undefined"!=typeof Uint8Array&&"undefined"!=typeof Uint16Array&&"undefined"!=typeof Int32Array;r.assign=function(t){for(var e=Array.prototype.slice.call(arguments,1);e.length;){var r=e.shift();if(r){if("object"!=typeof r)throw new TypeError(r+"must be non-object");for(var i in r)r.hasOwnProperty(i)&&(t[i]=r[i])}}return t},r.shrinkBuf=function(t,e){return t.length===e?t:t.subarray?t.subarray(0,e):(t.length=e,t)};var n={arraySet:function(t,e,r,i,n){if(e.subarray&&t.subarray)t.set(e.subarray(r,r+i),n);else for(var s=0;s<i;s++)t[n+s]=e[r+s]},flattenChunks:function(t){var e,r,i,n,s,a;for(e=i=0,r=t.length;e<r;e++)i+=t[e].length;for(a=new Uint8Array(i),e=n=0,r=t.length;e<r;e++)s=t[e],a.set(s,n),n+=s.length;return a}},s={arraySet:function(t,e,r,i,n){for(var s=0;s<i;s++)t[n+s]=e[r+s]},flattenChunks:function(t){return[].concat.apply([],t)}};r.setTyped=function(t){t?(r.Buf8=Uint8Array,r.Buf16=Uint16Array,r.Buf32=Int32Array,r.assign(r,n)):(r.Buf8=Array,r.Buf16=Array,r.Buf32=Array,r.assign(r,s))},r.setTyped(i)},{}],42:[function(t,e,r){"use strict";var h=t("./common"),n=!0,s=!0;try{String.fromCharCode.apply(null,[0])}catch(t){n=!1}try{String.fromCharCode.apply(null,new Uint8Array(1))}catch(t){s=!1}for(var u=new h.Buf8(256),i=0;i<256;i++)u[i]=252<=i?6:248<=i?5:240<=i?4:224<=i?3:192<=i?2:1;function l(t,e){if(e<65537&&(t.subarray&&s||!t.subarray&&n))return String.fromCharCode.apply(null,h.shrinkBuf(t,e));for(var r="",i=0;i<e;i++)r+=String.fromCharCode(t[i]);return r}u[254]=u[254]=1,r.string2buf=function(t){var e,r,i,n,s,a=t.length,o=0;for(n=0;n<a;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),o+=r<128?1:r<2048?2:r<65536?3:4;for(e=new h.Buf8(o),n=s=0;s<o;n++)55296==(64512&(r=t.charCodeAt(n)))&&n+1<a&&56320==(64512&(i=t.charCodeAt(n+1)))&&(r=65536+(r-55296<<10)+(i-56320),n++),r<128?e[s++]=r:(r<2048?e[s++]=192|r>>>6:(r<65536?e[s++]=224|r>>>12:(e[s++]=240|r>>>18,e[s++]=128|r>>>12&63),e[s++]=128|r>>>6&63),e[s++]=128|63&r);return e},r.buf2binstring=function(t){return l(t,t.length)},r.binstring2buf=function(t){for(var e=new h.Buf8(t.length),r=0,i=e.length;r<i;r++)e[r]=t.charCodeAt(r);return e},r.buf2string=function(t,e){var r,i,n,s,a=e||t.length,o=new Array(2*a);for(r=i=0;r<a;)if((n=t[r++])<128)o[i++]=n;else if(4<(s=u[n]))o[i++]=65533,r+=s-1;else{for(n&=2===s?31:3===s?15:7;1<s&&r<a;)n=n<<6|63&t[r++],s--;1<s?o[i++]=65533:n<65536?o[i++]=n:(n-=65536,o[i++]=55296|n>>10&1023,o[i++]=56320|1023&n)}return l(o,i)},r.utf8border=function(t,e){var r;for((e=e||t.length)>t.length&&(e=t.length),r=e-1;0<=r&&128==(192&t[r]);)r--;return r<0?e:0===r?e:r+u[t[r]]>e?r:e}},{"./common":41}],43:[function(t,e,r){"use strict";e.exports=function(t,e,r,i){for(var n=65535&t|0,s=t>>>16&65535|0,a=0;0!==r;){for(r-=a=2e3<r?2e3:r;s=s+(n=n+e[i++]|0)|0,--a;);n%=65521,s%=65521}return n|s<<16|0}},{}],44:[function(t,e,r){"use strict";e.exports={Z_NO_FLUSH:0,Z_PARTIAL_FLUSH:1,Z_SYNC_FLUSH:2,Z_FULL_FLUSH:3,Z_FINISH:4,Z_BLOCK:5,Z_TREES:6,Z_OK:0,Z_STREAM_END:1,Z_NEED_DICT:2,Z_ERRNO:-1,Z_STREAM_ERROR:-2,Z_DATA_ERROR:-3,Z_BUF_ERROR:-5,Z_NO_COMPRESSION:0,Z_BEST_SPEED:1,Z_BEST_COMPRESSION:9,Z_DEFAULT_COMPRESSION:-1,Z_FILTERED:1,Z_HUFFMAN_ONLY:2,Z_RLE:3,Z_FIXED:4,Z_DEFAULT_STRATEGY:0,Z_BINARY:0,Z_TEXT:1,Z_UNKNOWN:2,Z_DEFLATED:8}},{}],45:[function(t,e,r){"use strict";var o=function(){for(var t,e=[],r=0;r<256;r++){t=r;for(var i=0;i<8;i++)t=1&t?3988292384^t>>>1:t>>>1;e[r]=t}return e}();e.exports=function(t,e,r,i){var n=o,s=i+r;t^=-1;for(var a=i;a<s;a++)t=t>>>8^n[255&(t^e[a])];return-1^t}},{}],46:[function(t,e,r){"use strict";var h,d=t("../utils/common"),u=t("./trees"),c=t("./adler32"),p=t("./crc32"),i=t("./messages"),l=0,f=4,m=0,_=-2,g=-1,b=4,n=2,v=8,y=9,s=286,a=30,o=19,w=2*s+1,k=15,x=3,S=258,z=S+x+1,C=42,E=113,A=1,I=2,O=3,B=4;function R(t,e){return t.msg=i[e],e}function T(t){return(t<<1)-(4<t?9:0)}function D(t){for(var e=t.length;0<=--e;)t[e]=0}function F(t){var e=t.state,r=e.pending;r>t.avail_out&&(r=t.avail_out),0!==r&&(d.arraySet(t.output,e.pending_buf,e.pending_out,r,t.next_out),t.next_out+=r,e.pending_out+=r,t.total_out+=r,t.avail_out-=r,e.pending-=r,0===e.pending&&(e.pending_out=0))}function N(t,e){u._tr_flush_block(t,0<=t.block_start?t.block_start:-1,t.strstart-t.block_start,e),t.block_start=t.strstart,F(t.strm)}function U(t,e){t.pending_buf[t.pending++]=e}function P(t,e){t.pending_buf[t.pending++]=e>>>8&255,t.pending_buf[t.pending++]=255&e}function L(t,e){var r,i,n=t.max_chain_length,s=t.strstart,a=t.prev_length,o=t.nice_match,h=t.strstart>t.w_size-z?t.strstart-(t.w_size-z):0,u=t.window,l=t.w_mask,f=t.prev,d=t.strstart+S,c=u[s+a-1],p=u[s+a];t.prev_length>=t.good_match&&(n>>=2),o>t.lookahead&&(o=t.lookahead);do{if(u[(r=e)+a]===p&&u[r+a-1]===c&&u[r]===u[s]&&u[++r]===u[s+1]){s+=2,r++;do{}while(u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&u[++s]===u[++r]&&s<d);if(i=S-(d-s),s=d-S,a<i){if(t.match_start=e,o<=(a=i))break;c=u[s+a-1],p=u[s+a]}}}while((e=f[e&l])>h&&0!=--n);return a<=t.lookahead?a:t.lookahead}function j(t){var e,r,i,n,s,a,o,h,u,l,f=t.w_size;do{if(n=t.window_size-t.lookahead-t.strstart,t.strstart>=f+(f-z)){for(d.arraySet(t.window,t.window,f,f,0),t.match_start-=f,t.strstart-=f,t.block_start-=f,e=r=t.hash_size;i=t.head[--e],t.head[e]=f<=i?i-f:0,--r;);for(e=r=f;i=t.prev[--e],t.prev[e]=f<=i?i-f:0,--r;);n+=f}if(0===t.strm.avail_in)break;if(a=t.strm,o=t.window,h=t.strstart+t.lookahead,u=n,l=void 0,l=a.avail_in,u<l&&(l=u),r=0===l?0:(a.avail_in-=l,d.arraySet(o,a.input,a.next_in,l,h),1===a.state.wrap?a.adler=c(a.adler,o,l,h):2===a.state.wrap&&(a.adler=p(a.adler,o,l,h)),a.next_in+=l,a.total_in+=l,l),t.lookahead+=r,t.lookahead+t.insert>=x)for(s=t.strstart-t.insert,t.ins_h=t.window[s],t.ins_h=(t.ins_h<<t.hash_shift^t.window[s+1])&t.hash_mask;t.insert&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[s+x-1])&t.hash_mask,t.prev[s&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=s,s++,t.insert--,!(t.lookahead+t.insert<x)););}while(t.lookahead<z&&0!==t.strm.avail_in)}function Z(t,e){for(var r,i;;){if(t.lookahead<z){if(j(t),t.lookahead<z&&e===l)return A;if(0===t.lookahead)break}if(r=0,t.lookahead>=x&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!==r&&t.strstart-r<=t.w_size-z&&(t.match_length=L(t,r)),t.match_length>=x)if(i=u._tr_tally(t,t.strstart-t.match_start,t.match_length-x),t.lookahead-=t.match_length,t.match_length<=t.max_lazy_match&&t.lookahead>=x){for(t.match_length--;t.strstart++,t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart,0!=--t.match_length;);t.strstart++}else t.strstart+=t.match_length,t.match_length=0,t.ins_h=t.window[t.strstart],t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+1])&t.hash_mask;else i=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++;if(i&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=t.strstart<x-1?t.strstart:x-1,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}function W(t,e){for(var r,i,n;;){if(t.lookahead<z){if(j(t),t.lookahead<z&&e===l)return A;if(0===t.lookahead)break}if(r=0,t.lookahead>=x&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),t.prev_length=t.match_length,t.prev_match=t.match_start,t.match_length=x-1,0!==r&&t.prev_length<t.max_lazy_match&&t.strstart-r<=t.w_size-z&&(t.match_length=L(t,r),t.match_length<=5&&(1===t.strategy||t.match_length===x&&4096<t.strstart-t.match_start)&&(t.match_length=x-1)),t.prev_length>=x&&t.match_length<=t.prev_length){for(n=t.strstart+t.lookahead-x,i=u._tr_tally(t,t.strstart-1-t.prev_match,t.prev_length-x),t.lookahead-=t.prev_length-1,t.prev_length-=2;++t.strstart<=n&&(t.ins_h=(t.ins_h<<t.hash_shift^t.window[t.strstart+x-1])&t.hash_mask,r=t.prev[t.strstart&t.w_mask]=t.head[t.ins_h],t.head[t.ins_h]=t.strstart),0!=--t.prev_length;);if(t.match_available=0,t.match_length=x-1,t.strstart++,i&&(N(t,!1),0===t.strm.avail_out))return A}else if(t.match_available){if((i=u._tr_tally(t,0,t.window[t.strstart-1]))&&N(t,!1),t.strstart++,t.lookahead--,0===t.strm.avail_out)return A}else t.match_available=1,t.strstart++,t.lookahead--}return t.match_available&&(i=u._tr_tally(t,0,t.window[t.strstart-1]),t.match_available=0),t.insert=t.strstart<x-1?t.strstart:x-1,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}function M(t,e,r,i,n){this.good_length=t,this.max_lazy=e,this.nice_length=r,this.max_chain=i,this.func=n}function H(){this.strm=null,this.status=0,this.pending_buf=null,this.pending_buf_size=0,this.pending_out=0,this.pending=0,this.wrap=0,this.gzhead=null,this.gzindex=0,this.method=v,this.last_flush=-1,this.w_size=0,this.w_bits=0,this.w_mask=0,this.window=null,this.window_size=0,this.prev=null,this.head=null,this.ins_h=0,this.hash_size=0,this.hash_bits=0,this.hash_mask=0,this.hash_shift=0,this.block_start=0,this.match_length=0,this.prev_match=0,this.match_available=0,this.strstart=0,this.match_start=0,this.lookahead=0,this.prev_length=0,this.max_chain_length=0,this.max_lazy_match=0,this.level=0,this.strategy=0,this.good_match=0,this.nice_match=0,this.dyn_ltree=new d.Buf16(2*w),this.dyn_dtree=new d.Buf16(2*(2*a+1)),this.bl_tree=new d.Buf16(2*(2*o+1)),D(this.dyn_ltree),D(this.dyn_dtree),D(this.bl_tree),this.l_desc=null,this.d_desc=null,this.bl_desc=null,this.bl_count=new d.Buf16(k+1),this.heap=new d.Buf16(2*s+1),D(this.heap),this.heap_len=0,this.heap_max=0,this.depth=new d.Buf16(2*s+1),D(this.depth),this.l_buf=0,this.lit_bufsize=0,this.last_lit=0,this.d_buf=0,this.opt_len=0,this.static_len=0,this.matches=0,this.insert=0,this.bi_buf=0,this.bi_valid=0}function G(t){var e;return t&&t.state?(t.total_in=t.total_out=0,t.data_type=n,(e=t.state).pending=0,e.pending_out=0,e.wrap<0&&(e.wrap=-e.wrap),e.status=e.wrap?C:E,t.adler=2===e.wrap?0:1,e.last_flush=l,u._tr_init(e),m):R(t,_)}function K(t){var e=G(t);return e===m&&function(t){t.window_size=2*t.w_size,D(t.head),t.max_lazy_match=h[t.level].max_lazy,t.good_match=h[t.level].good_length,t.nice_match=h[t.level].nice_length,t.max_chain_length=h[t.level].max_chain,t.strstart=0,t.block_start=0,t.lookahead=0,t.insert=0,t.match_length=t.prev_length=x-1,t.match_available=0,t.ins_h=0}(t.state),e}function Y(t,e,r,i,n,s){if(!t)return _;var a=1;if(e===g&&(e=6),i<0?(a=0,i=-i):15<i&&(a=2,i-=16),n<1||y<n||r!==v||i<8||15<i||e<0||9<e||s<0||b<s)return R(t,_);8===i&&(i=9);var o=new H;return(t.state=o).strm=t,o.wrap=a,o.gzhead=null,o.w_bits=i,o.w_size=1<<o.w_bits,o.w_mask=o.w_size-1,o.hash_bits=n+7,o.hash_size=1<<o.hash_bits,o.hash_mask=o.hash_size-1,o.hash_shift=~~((o.hash_bits+x-1)/x),o.window=new d.Buf8(2*o.w_size),o.head=new d.Buf16(o.hash_size),o.prev=new d.Buf16(o.w_size),o.lit_bufsize=1<<n+6,o.pending_buf_size=4*o.lit_bufsize,o.pending_buf=new d.Buf8(o.pending_buf_size),o.d_buf=1*o.lit_bufsize,o.l_buf=3*o.lit_bufsize,o.level=e,o.strategy=s,o.method=r,K(t)}h=[new M(0,0,0,0,function(t,e){var r=65535;for(r>t.pending_buf_size-5&&(r=t.pending_buf_size-5);;){if(t.lookahead<=1){if(j(t),0===t.lookahead&&e===l)return A;if(0===t.lookahead)break}t.strstart+=t.lookahead,t.lookahead=0;var i=t.block_start+r;if((0===t.strstart||t.strstart>=i)&&(t.lookahead=t.strstart-i,t.strstart=i,N(t,!1),0===t.strm.avail_out))return A;if(t.strstart-t.block_start>=t.w_size-z&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):(t.strstart>t.block_start&&(N(t,!1),t.strm.avail_out),A)}),new M(4,4,8,4,Z),new M(4,5,16,8,Z),new M(4,6,32,32,Z),new M(4,4,16,16,W),new M(8,16,32,32,W),new M(8,16,128,128,W),new M(8,32,128,256,W),new M(32,128,258,1024,W),new M(32,258,258,4096,W)],r.deflateInit=function(t,e){return Y(t,e,v,15,8,0)},r.deflateInit2=Y,r.deflateReset=K,r.deflateResetKeep=G,r.deflateSetHeader=function(t,e){return t&&t.state?2!==t.state.wrap?_:(t.state.gzhead=e,m):_},r.deflate=function(t,e){var r,i,n,s;if(!t||!t.state||5<e||e<0)return t?R(t,_):_;if(i=t.state,!t.output||!t.input&&0!==t.avail_in||666===i.status&&e!==f)return R(t,0===t.avail_out?-5:_);if(i.strm=t,r=i.last_flush,i.last_flush=e,i.status===C)if(2===i.wrap)t.adler=0,U(i,31),U(i,139),U(i,8),i.gzhead?(U(i,(i.gzhead.text?1:0)+(i.gzhead.hcrc?2:0)+(i.gzhead.extra?4:0)+(i.gzhead.name?8:0)+(i.gzhead.comment?16:0)),U(i,255&i.gzhead.time),U(i,i.gzhead.time>>8&255),U(i,i.gzhead.time>>16&255),U(i,i.gzhead.time>>24&255),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,255&i.gzhead.os),i.gzhead.extra&&i.gzhead.extra.length&&(U(i,255&i.gzhead.extra.length),U(i,i.gzhead.extra.length>>8&255)),i.gzhead.hcrc&&(t.adler=p(t.adler,i.pending_buf,i.pending,0)),i.gzindex=0,i.status=69):(U(i,0),U(i,0),U(i,0),U(i,0),U(i,0),U(i,9===i.level?2:2<=i.strategy||i.level<2?4:0),U(i,3),i.status=E);else{var a=v+(i.w_bits-8<<4)<<8;a|=(2<=i.strategy||i.level<2?0:i.level<6?1:6===i.level?2:3)<<6,0!==i.strstart&&(a|=32),a+=31-a%31,i.status=E,P(i,a),0!==i.strstart&&(P(i,t.adler>>>16),P(i,65535&t.adler)),t.adler=1}if(69===i.status)if(i.gzhead.extra){for(n=i.pending;i.gzindex<(65535&i.gzhead.extra.length)&&(i.pending!==i.pending_buf_size||(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending!==i.pending_buf_size));)U(i,255&i.gzhead.extra[i.gzindex]),i.gzindex++;i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),i.gzindex===i.gzhead.extra.length&&(i.gzindex=0,i.status=73)}else i.status=73;if(73===i.status)if(i.gzhead.name){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindex<i.gzhead.name.length?255&i.gzhead.name.charCodeAt(i.gzindex++):0,U(i,s)}while(0!==s);i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.gzindex=0,i.status=91)}else i.status=91;if(91===i.status)if(i.gzhead.comment){n=i.pending;do{if(i.pending===i.pending_buf_size&&(i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),F(t),n=i.pending,i.pending===i.pending_buf_size)){s=1;break}s=i.gzindex<i.gzhead.comment.length?255&i.gzhead.comment.charCodeAt(i.gzindex++):0,U(i,s)}while(0!==s);i.gzhead.hcrc&&i.pending>n&&(t.adler=p(t.adler,i.pending_buf,i.pending-n,n)),0===s&&(i.status=103)}else i.status=103;if(103===i.status&&(i.gzhead.hcrc?(i.pending+2>i.pending_buf_size&&F(t),i.pending+2<=i.pending_buf_size&&(U(i,255&t.adler),U(i,t.adler>>8&255),t.adler=0,i.status=E)):i.status=E),0!==i.pending){if(F(t),0===t.avail_out)return i.last_flush=-1,m}else if(0===t.avail_in&&T(e)<=T(r)&&e!==f)return R(t,-5);if(666===i.status&&0!==t.avail_in)return R(t,-5);if(0!==t.avail_in||0!==i.lookahead||e!==l&&666!==i.status){var o=2===i.strategy?function(t,e){for(var r;;){if(0===t.lookahead&&(j(t),0===t.lookahead)){if(e===l)return A;break}if(t.match_length=0,r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++,r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):3===i.strategy?function(t,e){for(var r,i,n,s,a=t.window;;){if(t.lookahead<=S){if(j(t),t.lookahead<=S&&e===l)return A;if(0===t.lookahead)break}if(t.match_length=0,t.lookahead>=x&&0<t.strstart&&(i=a[n=t.strstart-1])===a[++n]&&i===a[++n]&&i===a[++n]){s=t.strstart+S;do{}while(i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&i===a[++n]&&n<s);t.match_length=S-(s-n),t.match_length>t.lookahead&&(t.match_length=t.lookahead)}if(t.match_length>=x?(r=u._tr_tally(t,1,t.match_length-x),t.lookahead-=t.match_length,t.strstart+=t.match_length,t.match_length=0):(r=u._tr_tally(t,0,t.window[t.strstart]),t.lookahead--,t.strstart++),r&&(N(t,!1),0===t.strm.avail_out))return A}return t.insert=0,e===f?(N(t,!0),0===t.strm.avail_out?O:B):t.last_lit&&(N(t,!1),0===t.strm.avail_out)?A:I}(i,e):h[i.level].func(i,e);if(o!==O&&o!==B||(i.status=666),o===A||o===O)return 0===t.avail_out&&(i.last_flush=-1),m;if(o===I&&(1===e?u._tr_align(i):5!==e&&(u._tr_stored_block(i,0,0,!1),3===e&&(D(i.head),0===i.lookahead&&(i.strstart=0,i.block_start=0,i.insert=0))),F(t),0===t.avail_out))return i.last_flush=-1,m}return e!==f?m:i.wrap<=0?1:(2===i.wrap?(U(i,255&t.adler),U(i,t.adler>>8&255),U(i,t.adler>>16&255),U(i,t.adler>>24&255),U(i,255&t.total_in),U(i,t.total_in>>8&255),U(i,t.total_in>>16&255),U(i,t.total_in>>24&255)):(P(i,t.adler>>>16),P(i,65535&t.adler)),F(t),0<i.wrap&&(i.wrap=-i.wrap),0!==i.pending?m:1)},r.deflateEnd=function(t){var e;return t&&t.state?(e=t.state.status)!==C&&69!==e&&73!==e&&91!==e&&103!==e&&e!==E&&666!==e?R(t,_):(t.state=null,e===E?R(t,-3):m):_},r.deflateSetDictionary=function(t,e){var r,i,n,s,a,o,h,u,l=e.length;if(!t||!t.state)return _;if(2===(s=(r=t.state).wrap)||1===s&&r.status!==C||r.lookahead)return _;for(1===s&&(t.adler=c(t.adler,e,l,0)),r.wrap=0,l>=r.w_size&&(0===s&&(D(r.head),r.strstart=0,r.block_start=0,r.insert=0),u=new d.Buf8(r.w_size),d.arraySet(u,e,l-r.w_size,r.w_size,0),e=u,l=r.w_size),a=t.avail_in,o=t.next_in,h=t.input,t.avail_in=l,t.next_in=0,t.input=e,j(r);r.lookahead>=x;){for(i=r.strstart,n=r.lookahead-(x-1);r.ins_h=(r.ins_h<<r.hash_shift^r.window[i+x-1])&r.hash_mask,r.prev[i&r.w_mask]=r.head[r.ins_h],r.head[r.ins_h]=i,i++,--n;);r.strstart=i,r.lookahead=x-1,j(r)}return r.strstart+=r.lookahead,r.block_start=r.strstart,r.insert=r.lookahead,r.lookahead=0,r.match_length=r.prev_length=x-1,r.match_available=0,t.next_in=o,t.input=h,t.avail_in=a,r.wrap=s,m},r.deflateInfo="pako deflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./messages":51,"./trees":52}],47:[function(t,e,r){"use strict";e.exports=function(){this.text=0,this.time=0,this.xflags=0,this.os=0,this.extra=null,this.extra_len=0,this.name="",this.comment="",this.hcrc=0,this.done=!1}},{}],48:[function(t,e,r){"use strict";e.exports=function(t,e){var r,i,n,s,a,o,h,u,l,f,d,c,p,m,_,g,b,v,y,w,k,x,S,z,C;r=t.state,i=t.next_in,z=t.input,n=i+(t.avail_in-5),s=t.next_out,C=t.output,a=s-(e-t.avail_out),o=s+(t.avail_out-257),h=r.dmax,u=r.wsize,l=r.whave,f=r.wnext,d=r.window,c=r.hold,p=r.bits,m=r.lencode,_=r.distcode,g=(1<<r.lenbits)-1,b=(1<<r.distbits)-1;t:do{p<15&&(c+=z[i++]<<p,p+=8,c+=z[i++]<<p,p+=8),v=m[c&g];e:for(;;){if(c>>>=y=v>>>24,p-=y,0===(y=v>>>16&255))C[s++]=65535&v;else{if(!(16&y)){if(0==(64&y)){v=m[(65535&v)+(c&(1<<y)-1)];continue e}if(32&y){r.mode=12;break t}t.msg="invalid literal/length code",r.mode=30;break t}w=65535&v,(y&=15)&&(p<y&&(c+=z[i++]<<p,p+=8),w+=c&(1<<y)-1,c>>>=y,p-=y),p<15&&(c+=z[i++]<<p,p+=8,c+=z[i++]<<p,p+=8),v=_[c&b];r:for(;;){if(c>>>=y=v>>>24,p-=y,!(16&(y=v>>>16&255))){if(0==(64&y)){v=_[(65535&v)+(c&(1<<y)-1)];continue r}t.msg="invalid distance code",r.mode=30;break t}if(k=65535&v,p<(y&=15)&&(c+=z[i++]<<p,(p+=8)<y&&(c+=z[i++]<<p,p+=8)),h<(k+=c&(1<<y)-1)){t.msg="invalid distance too far back",r.mode=30;break t}if(c>>>=y,p-=y,(y=s-a)<k){if(l<(y=k-y)&&r.sane){t.msg="invalid distance too far back",r.mode=30;break t}if(S=d,(x=0)===f){if(x+=u-y,y<w){for(w-=y;C[s++]=d[x++],--y;);x=s-k,S=C}}else if(f<y){if(x+=u+f-y,(y-=f)<w){for(w-=y;C[s++]=d[x++],--y;);if(x=0,f<w){for(w-=y=f;C[s++]=d[x++],--y;);x=s-k,S=C}}}else if(x+=f-y,y<w){for(w-=y;C[s++]=d[x++],--y;);x=s-k,S=C}for(;2<w;)C[s++]=S[x++],C[s++]=S[x++],C[s++]=S[x++],w-=3;w&&(C[s++]=S[x++],1<w&&(C[s++]=S[x++]))}else{for(x=s-k;C[s++]=C[x++],C[s++]=C[x++],C[s++]=C[x++],2<(w-=3););w&&(C[s++]=C[x++],1<w&&(C[s++]=C[x++]))}break}}break}}while(i<n&&s<o);i-=w=p>>3,c&=(1<<(p-=w<<3))-1,t.next_in=i,t.next_out=s,t.avail_in=i<n?n-i+5:5-(i-n),t.avail_out=s<o?o-s+257:257-(s-o),r.hold=c,r.bits=p}},{}],49:[function(t,e,r){"use strict";var I=t("../utils/common"),O=t("./adler32"),B=t("./crc32"),R=t("./inffast"),T=t("./inftrees"),D=1,F=2,N=0,U=-2,P=1,i=852,n=592;function L(t){return(t>>>24&255)+(t>>>8&65280)+((65280&t)<<8)+((255&t)<<24)}function s(){this.mode=0,this.last=!1,this.wrap=0,this.havedict=!1,this.flags=0,this.dmax=0,this.check=0,this.total=0,this.head=null,this.wbits=0,this.wsize=0,this.whave=0,this.wnext=0,this.window=null,this.hold=0,this.bits=0,this.length=0,this.offset=0,this.extra=0,this.lencode=null,this.distcode=null,this.lenbits=0,this.distbits=0,this.ncode=0,this.nlen=0,this.ndist=0,this.have=0,this.next=null,this.lens=new I.Buf16(320),this.work=new I.Buf16(288),this.lendyn=null,this.distdyn=null,this.sane=0,this.back=0,this.was=0}function a(t){var e;return t&&t.state?(e=t.state,t.total_in=t.total_out=e.total=0,t.msg="",e.wrap&&(t.adler=1&e.wrap),e.mode=P,e.last=0,e.havedict=0,e.dmax=32768,e.head=null,e.hold=0,e.bits=0,e.lencode=e.lendyn=new I.Buf32(i),e.distcode=e.distdyn=new I.Buf32(n),e.sane=1,e.back=-1,N):U}function o(t){var e;return t&&t.state?((e=t.state).wsize=0,e.whave=0,e.wnext=0,a(t)):U}function h(t,e){var r,i;return t&&t.state?(i=t.state,e<0?(r=0,e=-e):(r=1+(e>>4),e<48&&(e&=15)),e&&(e<8||15<e)?U:(null!==i.window&&i.wbits!==e&&(i.window=null),i.wrap=r,i.wbits=e,o(t))):U}function u(t,e){var r,i;return t?(i=new s,(t.state=i).window=null,(r=h(t,e))!==N&&(t.state=null),r):U}var l,f,d=!0;function j(t){if(d){var e;for(l=new I.Buf32(512),f=new I.Buf32(32),e=0;e<144;)t.lens[e++]=8;for(;e<256;)t.lens[e++]=9;for(;e<280;)t.lens[e++]=7;for(;e<288;)t.lens[e++]=8;for(T(D,t.lens,0,288,l,0,t.work,{bits:9}),e=0;e<32;)t.lens[e++]=5;T(F,t.lens,0,32,f,0,t.work,{bits:5}),d=!1}t.lencode=l,t.lenbits=9,t.distcode=f,t.distbits=5}function Z(t,e,r,i){var n,s=t.state;return null===s.window&&(s.wsize=1<<s.wbits,s.wnext=0,s.whave=0,s.window=new I.Buf8(s.wsize)),i>=s.wsize?(I.arraySet(s.window,e,r-s.wsize,s.wsize,0),s.wnext=0,s.whave=s.wsize):(i<(n=s.wsize-s.wnext)&&(n=i),I.arraySet(s.window,e,r-i,n,s.wnext),(i-=n)?(I.arraySet(s.window,e,r-i,i,0),s.wnext=i,s.whave=s.wsize):(s.wnext+=n,s.wnext===s.wsize&&(s.wnext=0),s.whave<s.wsize&&(s.whave+=n))),0}r.inflateReset=o,r.inflateReset2=h,r.inflateResetKeep=a,r.inflateInit=function(t){return u(t,15)},r.inflateInit2=u,r.inflate=function(t,e){var r,i,n,s,a,o,h,u,l,f,d,c,p,m,_,g,b,v,y,w,k,x,S,z,C=0,E=new I.Buf8(4),A=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];if(!t||!t.state||!t.output||!t.input&&0!==t.avail_in)return U;12===(r=t.state).mode&&(r.mode=13),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,f=o,d=h,x=N;t:for(;;)switch(r.mode){case P:if(0===r.wrap){r.mode=13;break}for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(2&r.wrap&&35615===u){E[r.check=0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0),l=u=0,r.mode=2;break}if(r.flags=0,r.head&&(r.head.done=!1),!(1&r.wrap)||(((255&u)<<8)+(u>>8))%31){t.msg="incorrect header check",r.mode=30;break}if(8!=(15&u)){t.msg="unknown compression method",r.mode=30;break}if(l-=4,k=8+(15&(u>>>=4)),0===r.wbits)r.wbits=k;else if(k>r.wbits){t.msg="invalid window size",r.mode=30;break}r.dmax=1<<k,t.adler=r.check=1,r.mode=512&u?10:12,l=u=0;break;case 2:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(r.flags=u,8!=(255&r.flags)){t.msg="unknown compression method",r.mode=30;break}if(57344&r.flags){t.msg="unknown header flags set",r.mode=30;break}r.head&&(r.head.text=u>>8&1),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=3;case 3:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.head&&(r.head.time=u),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,E[2]=u>>>16&255,E[3]=u>>>24&255,r.check=B(r.check,E,4,0)),l=u=0,r.mode=4;case 4:for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.head&&(r.head.xflags=255&u,r.head.os=u>>8),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0,r.mode=5;case 5:if(1024&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.length=u,r.head&&(r.head.extra_len=u),512&r.flags&&(E[0]=255&u,E[1]=u>>>8&255,r.check=B(r.check,E,2,0)),l=u=0}else r.head&&(r.head.extra=null);r.mode=6;case 6:if(1024&r.flags&&(o<(c=r.length)&&(c=o),c&&(r.head&&(k=r.head.extra_len-r.length,r.head.extra||(r.head.extra=new Array(r.head.extra_len)),I.arraySet(r.head.extra,i,s,c,k)),512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,r.length-=c),r.length))break t;r.length=0,r.mode=7;case 7:if(2048&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.name+=String.fromCharCode(k)),k&&c<o;);if(512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,k)break t}else r.head&&(r.head.name=null);r.length=0,r.mode=8;case 8:if(4096&r.flags){if(0===o)break t;for(c=0;k=i[s+c++],r.head&&k&&r.length<65536&&(r.head.comment+=String.fromCharCode(k)),k&&c<o;);if(512&r.flags&&(r.check=B(r.check,i,c,s)),o-=c,s+=c,k)break t}else r.head&&(r.head.comment=null);r.mode=9;case 9:if(512&r.flags){for(;l<16;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u!==(65535&r.check)){t.msg="header crc mismatch",r.mode=30;break}l=u=0}r.head&&(r.head.hcrc=r.flags>>9&1,r.head.done=!0),t.adler=r.check=0,r.mode=12;break;case 10:for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}t.adler=r.check=L(u),l=u=0,r.mode=11;case 11:if(0===r.havedict)return t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,2;t.adler=r.check=1,r.mode=12;case 12:if(5===e||6===e)break t;case 13:if(r.last){u>>>=7&l,l-=7&l,r.mode=27;break}for(;l<3;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}switch(r.last=1&u,l-=1,3&(u>>>=1)){case 0:r.mode=14;break;case 1:if(j(r),r.mode=20,6!==e)break;u>>>=2,l-=2;break t;case 2:r.mode=17;break;case 3:t.msg="invalid block type",r.mode=30}u>>>=2,l-=2;break;case 14:for(u>>>=7&l,l-=7&l;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if((65535&u)!=(u>>>16^65535)){t.msg="invalid stored block lengths",r.mode=30;break}if(r.length=65535&u,l=u=0,r.mode=15,6===e)break t;case 15:r.mode=16;case 16:if(c=r.length){if(o<c&&(c=o),h<c&&(c=h),0===c)break t;I.arraySet(n,i,s,c,a),o-=c,s+=c,h-=c,a+=c,r.length-=c;break}r.mode=12;break;case 17:for(;l<14;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(r.nlen=257+(31&u),u>>>=5,l-=5,r.ndist=1+(31&u),u>>>=5,l-=5,r.ncode=4+(15&u),u>>>=4,l-=4,286<r.nlen||30<r.ndist){t.msg="too many length or distance symbols",r.mode=30;break}r.have=0,r.mode=18;case 18:for(;r.have<r.ncode;){for(;l<3;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.lens[A[r.have++]]=7&u,u>>>=3,l-=3}for(;r.have<19;)r.lens[A[r.have++]]=0;if(r.lencode=r.lendyn,r.lenbits=7,S={bits:r.lenbits},x=T(0,r.lens,0,19,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid code lengths set",r.mode=30;break}r.have=0,r.mode=19;case 19:for(;r.have<r.nlen+r.ndist;){for(;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(b<16)u>>>=_,l-=_,r.lens[r.have++]=b;else{if(16===b){for(z=_+2;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u>>>=_,l-=_,0===r.have){t.msg="invalid bit length repeat",r.mode=30;break}k=r.lens[r.have-1],c=3+(3&u),u>>>=2,l-=2}else if(17===b){for(z=_+3;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}l-=_,k=0,c=3+(7&(u>>>=_)),u>>>=3,l-=3}else{for(z=_+7;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}l-=_,k=0,c=11+(127&(u>>>=_)),u>>>=7,l-=7}if(r.have+c>r.nlen+r.ndist){t.msg="invalid bit length repeat",r.mode=30;break}for(;c--;)r.lens[r.have++]=k}}if(30===r.mode)break;if(0===r.lens[256]){t.msg="invalid code -- missing end-of-block",r.mode=30;break}if(r.lenbits=9,S={bits:r.lenbits},x=T(D,r.lens,0,r.nlen,r.lencode,0,r.work,S),r.lenbits=S.bits,x){t.msg="invalid literal/lengths set",r.mode=30;break}if(r.distbits=6,r.distcode=r.distdyn,S={bits:r.distbits},x=T(F,r.lens,r.nlen,r.ndist,r.distcode,0,r.work,S),r.distbits=S.bits,x){t.msg="invalid distances set",r.mode=30;break}if(r.mode=20,6===e)break t;case 20:r.mode=21;case 21:if(6<=o&&258<=h){t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,R(t,d),a=t.next_out,n=t.output,h=t.avail_out,s=t.next_in,i=t.input,o=t.avail_in,u=r.hold,l=r.bits,12===r.mode&&(r.back=-1);break}for(r.back=0;g=(C=r.lencode[u&(1<<r.lenbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(g&&0==(240&g)){for(v=_,y=g,w=b;g=(C=r.lencode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,r.length=b,0===g){r.mode=26;break}if(32&g){r.back=-1,r.mode=12;break}if(64&g){t.msg="invalid literal/length code",r.mode=30;break}r.extra=15&g,r.mode=22;case 22:if(r.extra){for(z=r.extra;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.length+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}r.was=r.length,r.mode=23;case 23:for(;g=(C=r.distcode[u&(1<<r.distbits)-1])>>>16&255,b=65535&C,!((_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(0==(240&g)){for(v=_,y=g,w=b;g=(C=r.distcode[w+((u&(1<<v+y)-1)>>v)])>>>16&255,b=65535&C,!(v+(_=C>>>24)<=l);){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}u>>>=v,l-=v,r.back+=v}if(u>>>=_,l-=_,r.back+=_,64&g){t.msg="invalid distance code",r.mode=30;break}r.offset=b,r.extra=15&g,r.mode=24;case 24:if(r.extra){for(z=r.extra;l<z;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}r.offset+=u&(1<<r.extra)-1,u>>>=r.extra,l-=r.extra,r.back+=r.extra}if(r.offset>r.dmax){t.msg="invalid distance too far back",r.mode=30;break}r.mode=25;case 25:if(0===h)break t;if(c=d-h,r.offset>c){if((c=r.offset-c)>r.whave&&r.sane){t.msg="invalid distance too far back",r.mode=30;break}p=c>r.wnext?(c-=r.wnext,r.wsize-c):r.wnext-c,c>r.length&&(c=r.length),m=r.window}else m=n,p=a-r.offset,c=r.length;for(h<c&&(c=h),h-=c,r.length-=c;n[a++]=m[p++],--c;);0===r.length&&(r.mode=21);break;case 26:if(0===h)break t;n[a++]=r.length,h--,r.mode=21;break;case 27:if(r.wrap){for(;l<32;){if(0===o)break t;o--,u|=i[s++]<<l,l+=8}if(d-=h,t.total_out+=d,r.total+=d,d&&(t.adler=r.check=r.flags?B(r.check,n,d,a-d):O(r.check,n,d,a-d)),d=h,(r.flags?u:L(u))!==r.check){t.msg="incorrect data check",r.mode=30;break}l=u=0}r.mode=28;case 28:if(r.wrap&&r.flags){for(;l<32;){if(0===o)break t;o--,u+=i[s++]<<l,l+=8}if(u!==(4294967295&r.total)){t.msg="incorrect length check",r.mode=30;break}l=u=0}r.mode=29;case 29:x=1;break t;case 30:x=-3;break t;case 31:return-4;case 32:default:return U}return t.next_out=a,t.avail_out=h,t.next_in=s,t.avail_in=o,r.hold=u,r.bits=l,(r.wsize||d!==t.avail_out&&r.mode<30&&(r.mode<27||4!==e))&&Z(t,t.output,t.next_out,d-t.avail_out)?(r.mode=31,-4):(f-=t.avail_in,d-=t.avail_out,t.total_in+=f,t.total_out+=d,r.total+=d,r.wrap&&d&&(t.adler=r.check=r.flags?B(r.check,n,d,t.next_out-d):O(r.check,n,d,t.next_out-d)),t.data_type=r.bits+(r.last?64:0)+(12===r.mode?128:0)+(20===r.mode||15===r.mode?256:0),(0==f&&0===d||4===e)&&x===N&&(x=-5),x)},r.inflateEnd=function(t){if(!t||!t.state)return U;var e=t.state;return e.window&&(e.window=null),t.state=null,N},r.inflateGetHeader=function(t,e){var r;return t&&t.state?0==(2&(r=t.state).wrap)?U:((r.head=e).done=!1,N):U},r.inflateSetDictionary=function(t,e){var r,i=e.length;return t&&t.state?0!==(r=t.state).wrap&&11!==r.mode?U:11===r.mode&&O(1,e,i,0)!==r.check?-3:Z(t,e,i,i)?(r.mode=31,-4):(r.havedict=1,N):U},r.inflateInfo="pako inflate (from Nodeca project)"},{"../utils/common":41,"./adler32":43,"./crc32":45,"./inffast":48,"./inftrees":50}],50:[function(t,e,r){"use strict";var D=t("../utils/common"),F=[3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258,0,0],N=[16,16,16,16,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,16,72,78],U=[1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0],P=[16,16,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,26,26,27,27,28,28,29,29,64,64];e.exports=function(t,e,r,i,n,s,a,o){var h,u,l,f,d,c,p,m,_,g=o.bits,b=0,v=0,y=0,w=0,k=0,x=0,S=0,z=0,C=0,E=0,A=null,I=0,O=new D.Buf16(16),B=new D.Buf16(16),R=null,T=0;for(b=0;b<=15;b++)O[b]=0;for(v=0;v<i;v++)O[e[r+v]]++;for(k=g,w=15;1<=w&&0===O[w];w--);if(w<k&&(k=w),0===w)return n[s++]=20971520,n[s++]=20971520,o.bits=1,0;for(y=1;y<w&&0===O[y];y++);for(k<y&&(k=y),b=z=1;b<=15;b++)if(z<<=1,(z-=O[b])<0)return-1;if(0<z&&(0===t||1!==w))return-1;for(B[1]=0,b=1;b<15;b++)B[b+1]=B[b]+O[b];for(v=0;v<i;v++)0!==e[r+v]&&(a[B[e[r+v]]++]=v);if(c=0===t?(A=R=a,19):1===t?(A=F,I-=257,R=N,T-=257,256):(A=U,R=P,-1),b=y,d=s,S=v=E=0,l=-1,f=(C=1<<(x=k))-1,1===t&&852<C||2===t&&592<C)return 1;for(;;){for(p=b-S,_=a[v]<c?(m=0,a[v]):a[v]>c?(m=R[T+a[v]],A[I+a[v]]):(m=96,0),h=1<<b-S,y=u=1<<x;n[d+(E>>S)+(u-=h)]=p<<24|m<<16|_|0,0!==u;);for(h=1<<b-1;E&h;)h>>=1;if(0!==h?(E&=h-1,E+=h):E=0,v++,0==--O[b]){if(b===w)break;b=e[r+a[v]]}if(k<b&&(E&f)!==l){for(0===S&&(S=k),d+=y,z=1<<(x=b-S);x+S<w&&!((z-=O[x+S])<=0);)x++,z<<=1;if(C+=1<<x,1===t&&852<C||2===t&&592<C)return 1;n[l=E&f]=k<<24|x<<16|d-s|0}}return 0!==E&&(n[d+E]=b-S<<24|64<<16|0),o.bits=k,0}},{"../utils/common":41}],51:[function(t,e,r){"use strict";e.exports={2:"need dictionary",1:"stream end",0:"","-1":"file error","-2":"stream error","-3":"data error","-4":"insufficient memory","-5":"buffer error","-6":"incompatible version"}},{}],52:[function(t,e,r){"use strict";var n=t("../utils/common"),o=0,h=1;function i(t){for(var e=t.length;0<=--e;)t[e]=0}var s=0,a=29,u=256,l=u+1+a,f=30,d=19,_=2*l+1,g=15,c=16,p=7,m=256,b=16,v=17,y=18,w=[0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0],k=[0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13],x=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7],S=[16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15],z=new Array(2*(l+2));i(z);var C=new Array(2*f);i(C);var E=new Array(512);i(E);var A=new Array(256);i(A);var I=new Array(a);i(I);var O,B,R,T=new Array(f);function D(t,e,r,i,n){this.static_tree=t,this.extra_bits=e,this.extra_base=r,this.elems=i,this.max_length=n,this.has_stree=t&&t.length}function F(t,e){this.dyn_tree=t,this.max_code=0,this.stat_desc=e}function N(t){return t<256?E[t]:E[256+(t>>>7)]}function U(t,e){t.pending_buf[t.pending++]=255&e,t.pending_buf[t.pending++]=e>>>8&255}function P(t,e,r){t.bi_valid>c-r?(t.bi_buf|=e<<t.bi_valid&65535,U(t,t.bi_buf),t.bi_buf=e>>c-t.bi_valid,t.bi_valid+=r-c):(t.bi_buf|=e<<t.bi_valid&65535,t.bi_valid+=r)}function L(t,e,r){P(t,r[2*e],r[2*e+1])}function j(t,e){for(var r=0;r|=1&t,t>>>=1,r<<=1,0<--e;);return r>>>1}function Z(t,e,r){var i,n,s=new Array(g+1),a=0;for(i=1;i<=g;i++)s[i]=a=a+r[i-1]<<1;for(n=0;n<=e;n++){var o=t[2*n+1];0!==o&&(t[2*n]=j(s[o]++,o))}}function W(t){var e;for(e=0;e<l;e++)t.dyn_ltree[2*e]=0;for(e=0;e<f;e++)t.dyn_dtree[2*e]=0;for(e=0;e<d;e++)t.bl_tree[2*e]=0;t.dyn_ltree[2*m]=1,t.opt_len=t.static_len=0,t.last_lit=t.matches=0}function M(t){8<t.bi_valid?U(t,t.bi_buf):0<t.bi_valid&&(t.pending_buf[t.pending++]=t.bi_buf),t.bi_buf=0,t.bi_valid=0}function H(t,e,r,i){var n=2*e,s=2*r;return t[n]<t[s]||t[n]===t[s]&&i[e]<=i[r]}function G(t,e,r){for(var i=t.heap[r],n=r<<1;n<=t.heap_len&&(n<t.heap_len&&H(e,t.heap[n+1],t.heap[n],t.depth)&&n++,!H(e,i,t.heap[n],t.depth));)t.heap[r]=t.heap[n],r=n,n<<=1;t.heap[r]=i}function K(t,e,r){var i,n,s,a,o=0;if(0!==t.last_lit)for(;i=t.pending_buf[t.d_buf+2*o]<<8|t.pending_buf[t.d_buf+2*o+1],n=t.pending_buf[t.l_buf+o],o++,0===i?L(t,n,e):(L(t,(s=A[n])+u+1,e),0!==(a=w[s])&&P(t,n-=I[s],a),L(t,s=N(--i),r),0!==(a=k[s])&&P(t,i-=T[s],a)),o<t.last_lit;);L(t,m,e)}function Y(t,e){var r,i,n,s=e.dyn_tree,a=e.stat_desc.static_tree,o=e.stat_desc.has_stree,h=e.stat_desc.elems,u=-1;for(t.heap_len=0,t.heap_max=_,r=0;r<h;r++)0!==s[2*r]?(t.heap[++t.heap_len]=u=r,t.depth[r]=0):s[2*r+1]=0;for(;t.heap_len<2;)s[2*(n=t.heap[++t.heap_len]=u<2?++u:0)]=1,t.depth[n]=0,t.opt_len--,o&&(t.static_len-=a[2*n+1]);for(e.max_code=u,r=t.heap_len>>1;1<=r;r--)G(t,s,r);for(n=h;r=t.heap[1],t.heap[1]=t.heap[t.heap_len--],G(t,s,1),i=t.heap[1],t.heap[--t.heap_max]=r,t.heap[--t.heap_max]=i,s[2*n]=s[2*r]+s[2*i],t.depth[n]=(t.depth[r]>=t.depth[i]?t.depth[r]:t.depth[i])+1,s[2*r+1]=s[2*i+1]=n,t.heap[1]=n++,G(t,s,1),2<=t.heap_len;);t.heap[--t.heap_max]=t.heap[1],function(t,e){var r,i,n,s,a,o,h=e.dyn_tree,u=e.max_code,l=e.stat_desc.static_tree,f=e.stat_desc.has_stree,d=e.stat_desc.extra_bits,c=e.stat_desc.extra_base,p=e.stat_desc.max_length,m=0;for(s=0;s<=g;s++)t.bl_count[s]=0;for(h[2*t.heap[t.heap_max]+1]=0,r=t.heap_max+1;r<_;r++)p<(s=h[2*h[2*(i=t.heap[r])+1]+1]+1)&&(s=p,m++),h[2*i+1]=s,u<i||(t.bl_count[s]++,a=0,c<=i&&(a=d[i-c]),o=h[2*i],t.opt_len+=o*(s+a),f&&(t.static_len+=o*(l[2*i+1]+a)));if(0!==m){do{for(s=p-1;0===t.bl_count[s];)s--;t.bl_count[s]--,t.bl_count[s+1]+=2,t.bl_count[p]--,m-=2}while(0<m);for(s=p;0!==s;s--)for(i=t.bl_count[s];0!==i;)u<(n=t.heap[--r])||(h[2*n+1]!==s&&(t.opt_len+=(s-h[2*n+1])*h[2*n],h[2*n+1]=s),i--)}}(t,e),Z(s,u,t.bl_count)}function X(t,e,r){var i,n,s=-1,a=e[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),e[2*(r+1)+1]=65535,i=0;i<=r;i++)n=a,a=e[2*(i+1)+1],++o<h&&n===a||(o<u?t.bl_tree[2*n]+=o:0!==n?(n!==s&&t.bl_tree[2*n]++,t.bl_tree[2*b]++):o<=10?t.bl_tree[2*v]++:t.bl_tree[2*y]++,s=n,u=(o=0)===a?(h=138,3):n===a?(h=6,3):(h=7,4))}function V(t,e,r){var i,n,s=-1,a=e[1],o=0,h=7,u=4;for(0===a&&(h=138,u=3),i=0;i<=r;i++)if(n=a,a=e[2*(i+1)+1],!(++o<h&&n===a)){if(o<u)for(;L(t,n,t.bl_tree),0!=--o;);else 0!==n?(n!==s&&(L(t,n,t.bl_tree),o--),L(t,b,t.bl_tree),P(t,o-3,2)):o<=10?(L(t,v,t.bl_tree),P(t,o-3,3)):(L(t,y,t.bl_tree),P(t,o-11,7));s=n,u=(o=0)===a?(h=138,3):n===a?(h=6,3):(h=7,4)}}i(T);var q=!1;function J(t,e,r,i){P(t,(s<<1)+(i?1:0),3),function(t,e,r,i){M(t),i&&(U(t,r),U(t,~r)),n.arraySet(t.pending_buf,t.window,e,r,t.pending),t.pending+=r}(t,e,r,!0)}r._tr_init=function(t){q||(function(){var t,e,r,i,n,s=new Array(g+1);for(i=r=0;i<a-1;i++)for(I[i]=r,t=0;t<1<<w[i];t++)A[r++]=i;for(A[r-1]=i,i=n=0;i<16;i++)for(T[i]=n,t=0;t<1<<k[i];t++)E[n++]=i;for(n>>=7;i<f;i++)for(T[i]=n<<7,t=0;t<1<<k[i]-7;t++)E[256+n++]=i;for(e=0;e<=g;e++)s[e]=0;for(t=0;t<=143;)z[2*t+1]=8,t++,s[8]++;for(;t<=255;)z[2*t+1]=9,t++,s[9]++;for(;t<=279;)z[2*t+1]=7,t++,s[7]++;for(;t<=287;)z[2*t+1]=8,t++,s[8]++;for(Z(z,l+1,s),t=0;t<f;t++)C[2*t+1]=5,C[2*t]=j(t,5);O=new D(z,w,u+1,l,g),B=new D(C,k,0,f,g),R=new D(new Array(0),x,0,d,p)}(),q=!0),t.l_desc=new F(t.dyn_ltree,O),t.d_desc=new F(t.dyn_dtree,B),t.bl_desc=new F(t.bl_tree,R),t.bi_buf=0,t.bi_valid=0,W(t)},r._tr_stored_block=J,r._tr_flush_block=function(t,e,r,i){var n,s,a=0;0<t.level?(2===t.strm.data_type&&(t.strm.data_type=function(t){var e,r=4093624447;for(e=0;e<=31;e++,r>>>=1)if(1&r&&0!==t.dyn_ltree[2*e])return o;if(0!==t.dyn_ltree[18]||0!==t.dyn_ltree[20]||0!==t.dyn_ltree[26])return h;for(e=32;e<u;e++)if(0!==t.dyn_ltree[2*e])return h;return o}(t)),Y(t,t.l_desc),Y(t,t.d_desc),a=function(t){var e;for(X(t,t.dyn_ltree,t.l_desc.max_code),X(t,t.dyn_dtree,t.d_desc.max_code),Y(t,t.bl_desc),e=d-1;3<=e&&0===t.bl_tree[2*S[e]+1];e--);return t.opt_len+=3*(e+1)+5+5+4,e}(t),n=t.opt_len+3+7>>>3,(s=t.static_len+3+7>>>3)<=n&&(n=s)):n=s=r+5,r+4<=n&&-1!==e?J(t,e,r,i):4===t.strategy||s===n?(P(t,2+(i?1:0),3),K(t,z,C)):(P(t,4+(i?1:0),3),function(t,e,r,i){var n;for(P(t,e-257,5),P(t,r-1,5),P(t,i-4,4),n=0;n<i;n++)P(t,t.bl_tree[2*S[n]+1],3);V(t,t.dyn_ltree,e-1),V(t,t.dyn_dtree,r-1)}(t,t.l_desc.max_code+1,t.d_desc.max_code+1,a+1),K(t,t.dyn_ltree,t.dyn_dtree)),W(t),i&&M(t)},r._tr_tally=function(t,e,r){return t.pending_buf[t.d_buf+2*t.last_lit]=e>>>8&255,t.pending_buf[t.d_buf+2*t.last_lit+1]=255&e,t.pending_buf[t.l_buf+t.last_lit]=255&r,t.last_lit++,0===e?t.dyn_ltree[2*r]++:(t.matches++,e--,t.dyn_ltree[2*(A[r]+u+1)]++,t.dyn_dtree[2*N(e)]++),t.last_lit===t.lit_bufsize-1},r._tr_align=function(t){P(t,2,3),L(t,m,z),function(t){16===t.bi_valid?(U(t,t.bi_buf),t.bi_buf=0,t.bi_valid=0):8<=t.bi_valid&&(t.pending_buf[t.pending++]=255&t.bi_buf,t.bi_buf>>=8,t.bi_valid-=8)}(t)}},{"../utils/common":41}],53:[function(t,e,r){"use strict";e.exports=function(){this.input=null,this.next_in=0,this.avail_in=0,this.total_in=0,this.output=null,this.next_out=0,this.avail_out=0,this.total_out=0,this.msg="",this.state=null,this.data_type=2,this.adler=0}},{}],54:[function(t,e,r){"use strict";e.exports="function"==typeof setImmediate?setImmediate:function(){var t=[].slice.apply(arguments);t.splice(1,0,0),setTimeout.apply(null,t)}},{}]},{},[10])(10)});
src/arborator-draft/speedtest.oneBigConllTag.html ADDED
The diff for this file is too large to render. See raw diff
 
src/arborator-draft/speedtest.separateConllTags.html ADDED
The diff for this file is too large to render. See raw diff
 
src/evalatin2024-latinpipe/LICENSE ADDED
@@ -0,0 +1,373 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Mozilla Public License Version 2.0
2
+ ==================================
3
+
4
+ 1. Definitions
5
+ --------------
6
+
7
+ 1.1. "Contributor"
8
+ means each individual or legal entity that creates, contributes to
9
+ the creation of, or owns Covered Software.
10
+
11
+ 1.2. "Contributor Version"
12
+ means the combination of the Contributions of others (if any) used
13
+ by a Contributor and that particular Contributor's Contribution.
14
+
15
+ 1.3. "Contribution"
16
+ means Covered Software of a particular Contributor.
17
+
18
+ 1.4. "Covered Software"
19
+ means Source Code Form to which the initial Contributor has attached
20
+ the notice in Exhibit A, the Executable Form of such Source Code
21
+ Form, and Modifications of such Source Code Form, in each case
22
+ including portions thereof.
23
+
24
+ 1.5. "Incompatible With Secondary Licenses"
25
+ means
26
+
27
+ (a) that the initial Contributor has attached the notice described
28
+ in Exhibit B to the Covered Software; or
29
+
30
+ (b) that the Covered Software was made available under the terms of
31
+ version 1.1 or earlier of the License, but not also under the
32
+ terms of a Secondary License.
33
+
34
+ 1.6. "Executable Form"
35
+ means any form of the work other than Source Code Form.
36
+
37
+ 1.7. "Larger Work"
38
+ means a work that combines Covered Software with other material, in
39
+ a separate file or files, that is not Covered Software.
40
+
41
+ 1.8. "License"
42
+ means this document.
43
+
44
+ 1.9. "Licensable"
45
+ means having the right to grant, to the maximum extent possible,
46
+ whether at the time of the initial grant or subsequently, any and
47
+ all of the rights conveyed by this License.
48
+
49
+ 1.10. "Modifications"
50
+ means any of the following:
51
+
52
+ (a) any file in Source Code Form that results from an addition to,
53
+ deletion from, or modification of the contents of Covered
54
+ Software; or
55
+
56
+ (b) any new file in Source Code Form that contains any Covered
57
+ Software.
58
+
59
+ 1.11. "Patent Claims" of a Contributor
60
+ means any patent claim(s), including without limitation, method,
61
+ process, and apparatus claims, in any patent Licensable by such
62
+ Contributor that would be infringed, but for the grant of the
63
+ License, by the making, using, selling, offering for sale, having
64
+ made, import, or transfer of either its Contributions or its
65
+ Contributor Version.
66
+
67
+ 1.12. "Secondary License"
68
+ means either the GNU General Public License, Version 2.0, the GNU
69
+ Lesser General Public License, Version 2.1, the GNU Affero General
70
+ Public License, Version 3.0, or any later versions of those
71
+ licenses.
72
+
73
+ 1.13. "Source Code Form"
74
+ means the form of the work preferred for making modifications.
75
+
76
+ 1.14. "You" (or "Your")
77
+ means an individual or a legal entity exercising rights under this
78
+ License. For legal entities, "You" includes any entity that
79
+ controls, is controlled by, or is under common control with You. For
80
+ purposes of this definition, "control" means (a) the power, direct
81
+ or indirect, to cause the direction or management of such entity,
82
+ whether by contract or otherwise, or (b) ownership of more than
83
+ fifty percent (50%) of the outstanding shares or beneficial
84
+ ownership of such entity.
85
+
86
+ 2. License Grants and Conditions
87
+ --------------------------------
88
+
89
+ 2.1. Grants
90
+
91
+ Each Contributor hereby grants You a world-wide, royalty-free,
92
+ non-exclusive license:
93
+
94
+ (a) under intellectual property rights (other than patent or trademark)
95
+ Licensable by such Contributor to use, reproduce, make available,
96
+ modify, display, perform, distribute, and otherwise exploit its
97
+ Contributions, either on an unmodified basis, with Modifications, or
98
+ as part of a Larger Work; and
99
+
100
+ (b) under Patent Claims of such Contributor to make, use, sell, offer
101
+ for sale, have made, import, and otherwise transfer either its
102
+ Contributions or its Contributor Version.
103
+
104
+ 2.2. Effective Date
105
+
106
+ The licenses granted in Section 2.1 with respect to any Contribution
107
+ become effective for each Contribution on the date the Contributor first
108
+ distributes such Contribution.
109
+
110
+ 2.3. Limitations on Grant Scope
111
+
112
+ The licenses granted in this Section 2 are the only rights granted under
113
+ this License. No additional rights or licenses will be implied from the
114
+ distribution or licensing of Covered Software under this License.
115
+ Notwithstanding Section 2.1(b) above, no patent license is granted by a
116
+ Contributor:
117
+
118
+ (a) for any code that a Contributor has removed from Covered Software;
119
+ or
120
+
121
+ (b) for infringements caused by: (i) Your and any other third party's
122
+ modifications of Covered Software, or (ii) the combination of its
123
+ Contributions with other software (except as part of its Contributor
124
+ Version); or
125
+
126
+ (c) under Patent Claims infringed by Covered Software in the absence of
127
+ its Contributions.
128
+
129
+ This License does not grant any rights in the trademarks, service marks,
130
+ or logos of any Contributor (except as may be necessary to comply with
131
+ the notice requirements in Section 3.4).
132
+
133
+ 2.4. Subsequent Licenses
134
+
135
+ No Contributor makes additional grants as a result of Your choice to
136
+ distribute the Covered Software under a subsequent version of this
137
+ License (see Section 10.2) or under the terms of a Secondary License (if
138
+ permitted under the terms of Section 3.3).
139
+
140
+ 2.5. Representation
141
+
142
+ Each Contributor represents that the Contributor believes its
143
+ Contributions are its original creation(s) or it has sufficient rights
144
+ to grant the rights to its Contributions conveyed by this License.
145
+
146
+ 2.6. Fair Use
147
+
148
+ This License is not intended to limit any rights You have under
149
+ applicable copyright doctrines of fair use, fair dealing, or other
150
+ equivalents.
151
+
152
+ 2.7. Conditions
153
+
154
+ Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
155
+ in Section 2.1.
156
+
157
+ 3. Responsibilities
158
+ -------------------
159
+
160
+ 3.1. Distribution of Source Form
161
+
162
+ All distribution of Covered Software in Source Code Form, including any
163
+ Modifications that You create or to which You contribute, must be under
164
+ the terms of this License. You must inform recipients that the Source
165
+ Code Form of the Covered Software is governed by the terms of this
166
+ License, and how they can obtain a copy of this License. You may not
167
+ attempt to alter or restrict the recipients' rights in the Source Code
168
+ Form.
169
+
170
+ 3.2. Distribution of Executable Form
171
+
172
+ If You distribute Covered Software in Executable Form then:
173
+
174
+ (a) such Covered Software must also be made available in Source Code
175
+ Form, as described in Section 3.1, and You must inform recipients of
176
+ the Executable Form how they can obtain a copy of such Source Code
177
+ Form by reasonable means in a timely manner, at a charge no more
178
+ than the cost of distribution to the recipient; and
179
+
180
+ (b) You may distribute such Executable Form under the terms of this
181
+ License, or sublicense it under different terms, provided that the
182
+ license for the Executable Form does not attempt to limit or alter
183
+ the recipients' rights in the Source Code Form under this License.
184
+
185
+ 3.3. Distribution of a Larger Work
186
+
187
+ You may create and distribute a Larger Work under terms of Your choice,
188
+ provided that You also comply with the requirements of this License for
189
+ the Covered Software. If the Larger Work is a combination of Covered
190
+ Software with a work governed by one or more Secondary Licenses, and the
191
+ Covered Software is not Incompatible With Secondary Licenses, this
192
+ License permits You to additionally distribute such Covered Software
193
+ under the terms of such Secondary License(s), so that the recipient of
194
+ the Larger Work may, at their option, further distribute the Covered
195
+ Software under the terms of either this License or such Secondary
196
+ License(s).
197
+
198
+ 3.4. Notices
199
+
200
+ You may not remove or alter the substance of any license notices
201
+ (including copyright notices, patent notices, disclaimers of warranty,
202
+ or limitations of liability) contained within the Source Code Form of
203
+ the Covered Software, except that You may alter any license notices to
204
+ the extent required to remedy known factual inaccuracies.
205
+
206
+ 3.5. Application of Additional Terms
207
+
208
+ You may choose to offer, and to charge a fee for, warranty, support,
209
+ indemnity or liability obligations to one or more recipients of Covered
210
+ Software. However, You may do so only on Your own behalf, and not on
211
+ behalf of any Contributor. You must make it absolutely clear that any
212
+ such warranty, support, indemnity, or liability obligation is offered by
213
+ You alone, and You hereby agree to indemnify every Contributor for any
214
+ liability incurred by such Contributor as a result of warranty, support,
215
+ indemnity or liability terms You offer. You may include additional
216
+ disclaimers of warranty and limitations of liability specific to any
217
+ jurisdiction.
218
+
219
+ 4. Inability to Comply Due to Statute or Regulation
220
+ ---------------------------------------------------
221
+
222
+ If it is impossible for You to comply with any of the terms of this
223
+ License with respect to some or all of the Covered Software due to
224
+ statute, judicial order, or regulation then You must: (a) comply with
225
+ the terms of this License to the maximum extent possible; and (b)
226
+ describe the limitations and the code they affect. Such description must
227
+ be placed in a text file included with all distributions of the Covered
228
+ Software under this License. Except to the extent prohibited by statute
229
+ or regulation, such description must be sufficiently detailed for a
230
+ recipient of ordinary skill to be able to understand it.
231
+
232
+ 5. Termination
233
+ --------------
234
+
235
+ 5.1. The rights granted under this License will terminate automatically
236
+ if You fail to comply with any of its terms. However, if You become
237
+ compliant, then the rights granted under this License from a particular
238
+ Contributor are reinstated (a) provisionally, unless and until such
239
+ Contributor explicitly and finally terminates Your grants, and (b) on an
240
+ ongoing basis, if such Contributor fails to notify You of the
241
+ non-compliance by some reasonable means prior to 60 days after You have
242
+ come back into compliance. Moreover, Your grants from a particular
243
+ Contributor are reinstated on an ongoing basis if such Contributor
244
+ notifies You of the non-compliance by some reasonable means, this is the
245
+ first time You have received notice of non-compliance with this License
246
+ from such Contributor, and You become compliant prior to 30 days after
247
+ Your receipt of the notice.
248
+
249
+ 5.2. If You initiate litigation against any entity by asserting a patent
250
+ infringement claim (excluding declaratory judgment actions,
251
+ counter-claims, and cross-claims) alleging that a Contributor Version
252
+ directly or indirectly infringes any patent, then the rights granted to
253
+ You by any and all Contributors for the Covered Software under Section
254
+ 2.1 of this License shall terminate.
255
+
256
+ 5.3. In the event of termination under Sections 5.1 or 5.2 above, all
257
+ end user license agreements (excluding distributors and resellers) which
258
+ have been validly granted by You or Your distributors under this License
259
+ prior to termination shall survive termination.
260
+
261
+ ************************************************************************
262
+ * *
263
+ * 6. Disclaimer of Warranty *
264
+ * ------------------------- *
265
+ * *
266
+ * Covered Software is provided under this License on an "as is" *
267
+ * basis, without warranty of any kind, either expressed, implied, or *
268
+ * statutory, including, without limitation, warranties that the *
269
+ * Covered Software is free of defects, merchantable, fit for a *
270
+ * particular purpose or non-infringing. The entire risk as to the *
271
+ * quality and performance of the Covered Software is with You. *
272
+ * Should any Covered Software prove defective in any respect, You *
273
+ * (not any Contributor) assume the cost of any necessary servicing, *
274
+ * repair, or correction. This disclaimer of warranty constitutes an *
275
+ * essential part of this License. No use of any Covered Software is *
276
+ * authorized under this License except under this disclaimer. *
277
+ * *
278
+ ************************************************************************
279
+
280
+ ************************************************************************
281
+ * *
282
+ * 7. Limitation of Liability *
283
+ * -------------------------- *
284
+ * *
285
+ * Under no circumstances and under no legal theory, whether tort *
286
+ * (including negligence), contract, or otherwise, shall any *
287
+ * Contributor, or anyone who distributes Covered Software as *
288
+ * permitted above, be liable to You for any direct, indirect, *
289
+ * special, incidental, or consequential damages of any character *
290
+ * including, without limitation, damages for lost profits, loss of *
291
+ * goodwill, work stoppage, computer failure or malfunction, or any *
292
+ * and all other commercial damages or losses, even if such party *
293
+ * shall have been informed of the possibility of such damages. This *
294
+ * limitation of liability shall not apply to liability for death or *
295
+ * personal injury resulting from such party's negligence to the *
296
+ * extent applicable law prohibits such limitation. Some *
297
+ * jurisdictions do not allow the exclusion or limitation of *
298
+ * incidental or consequential damages, so this exclusion and *
299
+ * limitation may not apply to You. *
300
+ * *
301
+ ************************************************************************
302
+
303
+ 8. Litigation
304
+ -------------
305
+
306
+ Any litigation relating to this License may be brought only in the
307
+ courts of a jurisdiction where the defendant maintains its principal
308
+ place of business and such litigation shall be governed by laws of that
309
+ jurisdiction, without reference to its conflict-of-law provisions.
310
+ Nothing in this Section shall prevent a party's ability to bring
311
+ cross-claims or counter-claims.
312
+
313
+ 9. Miscellaneous
314
+ ----------------
315
+
316
+ This License represents the complete agreement concerning the subject
317
+ matter hereof. If any provision of this License is held to be
318
+ unenforceable, such provision shall be reformed only to the extent
319
+ necessary to make it enforceable. Any law or regulation which provides
320
+ that the language of a contract shall be construed against the drafter
321
+ shall not be used to construe this License against a Contributor.
322
+
323
+ 10. Versions of the License
324
+ ---------------------------
325
+
326
+ 10.1. New Versions
327
+
328
+ Mozilla Foundation is the license steward. Except as provided in Section
329
+ 10.3, no one other than the license steward has the right to modify or
330
+ publish new versions of this License. Each version will be given a
331
+ distinguishing version number.
332
+
333
+ 10.2. Effect of New Versions
334
+
335
+ You may distribute the Covered Software under the terms of the version
336
+ of the License under which You originally received the Covered Software,
337
+ or under the terms of any subsequent version published by the license
338
+ steward.
339
+
340
+ 10.3. Modified Versions
341
+
342
+ If you create software not governed by this License, and you want to
343
+ create a new license for such software, you may create and use a
344
+ modified version of this License if you rename the license and remove
345
+ any references to the name of the license steward (except to note that
346
+ such modified license differs from this License).
347
+
348
+ 10.4. Distributing Source Code Form that is Incompatible With Secondary
349
+ Licenses
350
+
351
+ If You choose to distribute Source Code Form that is Incompatible With
352
+ Secondary Licenses under the terms of this version of the License, the
353
+ notice described in Exhibit B of this License must be attached.
354
+
355
+ Exhibit A - Source Code Form License Notice
356
+ -------------------------------------------
357
+
358
+ This Source Code Form is subject to the terms of the Mozilla Public
359
+ License, v. 2.0. If a copy of the MPL was not distributed with this
360
+ file, You can obtain one at http://mozilla.org/MPL/2.0/.
361
+
362
+ If it is not possible or desirable to put the notice in a particular
363
+ file, then You may include the notice in a location (such as a LICENSE
364
+ file in a relevant directory) where a recipient would be likely to look
365
+ for such a notice.
366
+
367
+ You may add additional accurate notices of copyright ownership.
368
+
369
+ Exhibit B - "Incompatible With Secondary Licenses" Notice
370
+ ---------------------------------------------------------
371
+
372
+ This Source Code Form is "Incompatible With Secondary Licenses", as
373
+ defined by the Mozilla Public License, v. 2.0.
src/evalatin2024-latinpipe/README.md ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # ÚFAL LatinPipe at EvaLatin 2024: Morphosyntactic Analysis of Latin
2
+
3
+ This repository contains the LatinPipe parser implementation described in
4
+ the _ÚFAL LatinPipe at EvaLatin 2024: Morphosyntactic Analysis of Latin_ paper.
5
+
6
+ 📢 Besides this source code and the [trained model](https://hdl.handle.net/11234/1-5671),
7
+ LatinPipe is also available in the [UDPipe LINDAT/CLARIN service](http://lindat.mff.cuni.cz/services/udpipe/)
8
+ and can be used either in a web form or through a REST service.
9
+
10
+ ---
11
+
12
+ <img src="figures/LatinPipe.svg" alt="LatinPipe Architecture" align="right" style="width: 45%">
13
+
14
+ <h3 align="center"><a href="https://aclanthology.org/2024.lt4hala-1.24/">ÚFAL LatinPipe at EvaLatin 2024: Morphosyntactic Analysis of Latin</a></h3>
15
+
16
+ <p align="center">
17
+ <b>Milan Straka</b> and <b>Jana Straková</b> and <b>Federica Gamba</b><br>
18
+ Charles University<br>
19
+ Faculty of Mathematics and Physics<br>
20
+ Institute of Formal and Applied Lingustics<br>
21
+ Malostranské nám. 25, Prague, Czech Republic
22
+ </p>
23
+
24
+ **Abstract:** We present LatinPipe, the winning submission to the EvaLatin 2024
25
+ Dependency Parsing shared task. Our system consists of a fine-tuned
26
+ concatenation of base and large pre-trained LMs, with a dot-product attention
27
+ head for parsing and softmax classification heads for morphology to jointly
28
+ learn both dependency parsing and morphological analysis. It is trained by
29
+ sampling from seven publicly available Latin corpora, utilizing additional
30
+ harmonization of annotations to achieve a more unified annotation style. Before
31
+ fine-tuning, we train the system for a few initial epochs with frozen weights.
32
+ We also add additional local relative contextualization by stacking the BiLSTM
33
+ layers on top of the Transformer(s). Finally, we ensemble output probability
34
+ distributions from seven randomly instantiated networks for the final
35
+ submission. The code is available at <a href="https://github.com/ufal/evalatin2024-latinpipe">https://github.com/ufal/evalatin2024-latinpipe</a>.<br clear="both">
36
+
37
+ ---
38
+
39
+ ## Content of this Repository
40
+
41
+ - The directory `data` is for all the required data (UD 2.13 data, harmonized
42
+ PROIEL, Sabellicus, Archimedes Latinus, EvaLatin 2024 test data).
43
+ - The script `data/fetch_data.sh` downloads and extracts all the data:
44
+ ```sh
45
+ (cd data && sh fetch_data.sh)
46
+ ```
47
+
48
+ - The `latinpipe_evalatin24.py` is the LatinPipe EvaLatin24 source.
49
+ - It depends on `latinpipe_evalatin24_eval.py`, which is a modularized version
50
+ of the official evaluation script.
51
+
52
+ - The `latinpipe_evalatin24_server.py` is a REST server with UDPipe-2-compatible
53
+ API, using `latinpipe_evalatin24.py` to perform tagging and parsing.
54
+
55
+ ## The Released `latinpipe-evalatin24-240520` Model
56
+
57
+ The `latinpipe-evalatin24-240520` is a `PhilBerta`-based model for tagging,
58
+ lemmatization, and dependency parsing of Latin, based on the winning entry
59
+ to the EvaLatin 2024 <https://circse.github.io/LT4HALA/2024/EvaLatin> shared
60
+ task. It is released at https://hdl.handle.net/11234/1-5671 under the CC
61
+ BY-NC-SA 4.0 license.
62
+
63
+ The model is also available in the [UDPipe LINDAT/CLARIN service](http://lindat.mff.cuni.cz/services/udpipe/)
64
+ and can be used either in a web form or through a REST service.
65
+
66
+ See the [latinpipe-evalatin24-240520 directory](latinpipe-evalatin24-240520/) for
67
+ the download link, the model performance, and additional information.
68
+
69
+ ## Training a Model
70
+
71
+ To train a model on all data, you should
72
+ 1. run the `data/fetch_data.sh` script to download all required data,
73
+ 2. create a Python environments with the packages listed in `requirements.txt`,
74
+ 3. train the model itself using the `latinpipe_evalatin24.py` script.
75
+
76
+ To train a model performing UPOS/UFeats tagging, lemmatization, and
77
+ dependency parsing, we use
78
+ ```sh
79
+ la_ud213_all="la_ittb la_llct la_perseus la_proiel la_udante"
80
+ la_other="la_archimedes la_sabellicus"
81
+ transformer="bowphs/PhilBerta" # or bowphs/LaBerta
82
+
83
+ latinpipe_evalatin24.py $(for split in dev test train; do echo --$split; for tb in $la_ud213_all; do [ $tb-$split = la_proiel-train ] && tb=la_proielh; echo data/$tb/$tb-ud-$split.conllu; done; done) $(for tb in $la_other; do echo data/$tb/$tb-train.conllu; done) --transformers $transformer --epochs=30 --exp=evalatin24_model --subword_combination=last --epochs_frozen=10 --batch_size=64 --save_checkpoint
84
+ ```
85
+
86
+ ## Predicting with a Trained Model
87
+
88
+ To predict with a trained model, you can use the following command:
89
+ ```sh
90
+ latinpipe_evalatin24.py --load evalatin24_model/model.weights.h5 --exp target_directory --test input1.conllu input2.conllu
91
+ ```
92
+ - the outputs are generated in the target directory, with a `.predicted.conllu` suffix;
93
+ - if you want to also evaluate the predicted files, you can use `--dev` option instead of `--test`.
94
+
95
+ ---
96
+
97
+ ## Contact
98
+
99
+ Milan Straka: ``[email protected]``\
100
+ Jana Straková: ``[email protected]``\
101
+ Federica Gamba: ``[email protected]``
102
+
103
+ ## How to Cite
104
+
105
+ ```
106
+ @inproceedings{straka-etal-2024-ufal,
107
+ title = "{{\'U}FAL} {L}atin{P}ipe at {E}va{L}atin 2024: Morphosyntactic Analysis of {L}atin",
108
+ author = "Straka, Milan and Strakov{\'a}, Jana and Gamba, Federica",
109
+ editor = "Sprugnoli, Rachele and Passarotti, Marco",
110
+ booktitle = "Proceedings of the Third Workshop on Language Technologies for Historical and Ancient Languages (LT4HALA) @ LREC-COLING-2024",
111
+ month = may,
112
+ year = "2024",
113
+ address = "Torino, Italia",
114
+ publisher = "ELRA and ICCL",
115
+ url = "https://aclanthology.org/2024.lt4hala-1.24",
116
+ pages = "207--214"
117
+ }
118
+ ```
src/evalatin2024-latinpipe/__pycache__/latinpipe_evalatin24_eval.cpython-311.pyc ADDED
Binary file (37.2 kB). View file
 
src/evalatin2024-latinpipe/data/conllu_split.py ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ #
3
+ # This file is part of LatinPipe EvaLatin 24
4
+ # <https://github.com/ufal/evalatin2024-latinpipe>.
5
+ #
6
+ # Copyright 2024 Institute of Formal and Applied Linguistics, Faculty of
7
+ # Mathematics and Physics, Charles University in Prague, Czech Republic.
8
+ #
9
+ # This Source Code Form is subject to the terms of the Mozilla Public
10
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
11
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
+ import argparse
13
+
14
+ import numpy as np
15
+
16
+ if __name__ == "__main__":
17
+ parser = argparse.ArgumentParser()
18
+ parser.add_argument("source", type=str, help="CoNLL-U file to split")
19
+ parser.add_argument("train", type=str, help="CoNLL-U file to write training data to")
20
+ parser.add_argument("dev", type=str, help="CoNLL-U file to write development data to")
21
+ parser.add_argument("--dev_size", type=float, default=0.1, help="Size of the development data")
22
+ args = parser.parse_args()
23
+
24
+ sentences = []
25
+ with open(args.source, "r", encoding="utf-8") as source:
26
+ sentence = []
27
+ for line in source:
28
+ sentence.append(line)
29
+ if not line.rstrip("\r\n"):
30
+ sentences.append("".join(sentence))
31
+ sentence = []
32
+ assert not sentence, "Missing empty line after the last sentence"
33
+
34
+ dev_indices = set(np.random.RandomState(42).choice(len(sentences), int(len(sentences) * args.dev_size), replace=False))
35
+
36
+ with open(args.train, "w", encoding="utf-8") as train:
37
+ with open(args.dev, "w", encoding="utf-8") as dev:
38
+ for i, sentence in enumerate(sentences):
39
+ (dev if i in dev_indices else train).write(sentence)
src/evalatin2024-latinpipe/data/fetch_data.sh ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/bin/bash
2
+ #
3
+ # This file is part of LatinPipe EvaLatin 24
4
+ # <https://github.com/ufal/evalatin2024-latinpipe>.
5
+ #
6
+ # Copyright 2024 Institute of Formal and Applied Linguistics, Faculty of
7
+ # Mathematics and Physics, Charles University in Prague, Czech Republic.
8
+ #
9
+ # This Source Code Form is subject to the terms of the Mozilla Public
10
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
11
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
+
13
+ # Refresh conllu_to_text.pl
14
+ curl -O https://raw.githubusercontent.com/UniversalDependencies/tools/master/conllu_to_text.pl
15
+
16
+ # Get the UD 2.13 data
17
+ curl -O https://lindat.mff.cuni.cz/repository/xmlui/bitstream/handle/11234/1-5287/ud-treebanks-v2.13.tgz
18
+ tar xf ud-treebanks-v2.13.tgz
19
+
20
+ for tb in ud-treebanks-v2.13/*Latin*/*-ud-train.conllu; do
21
+ dir=`dirname $tb`
22
+ long_name=`basename $dir`
23
+ code=`basename $tb`
24
+ code=${code%%-*}
25
+ echo Fetching $long_name as $code
26
+
27
+ mkdir -p $code
28
+ cp $dir/* $code
29
+ if [ ! -f $code/$code-ud-dev.conllu ]; then
30
+ python3 conllu_split.py $dir/$code-ud-train.conllu $code/$code-ud-train.conllu $code/$code-ud-dev.conllu
31
+ for conllu in $code/$code-ud-train.conllu $code/$code-ud-dev.conllu; do
32
+ perl conllu_to_text.pl --language=$code <$conllu >${conllu%.conllu}.txt
33
+ done
34
+ fi
35
+ done
36
+ rm -rf ud-treebanks-v2.13.tgz ud-treebanks-v2.13/
37
+
38
+ for dir in */; do
39
+ echo "${dir%/} $(grep -cP "^\d+\t" $dir*train.conllu)"
40
+ done | sort -rnk2 >langs_sizes
41
+
42
+ # Get the non-UD small datasets
43
+ corpus=la_sabellicus
44
+ echo Fetching $corpus
45
+ mkdir -p $corpus
46
+ wget https://raw.githubusercontent.com/CIRCSE/Sabellicus/main/Sabellicus_DeLatinaeLinguaeReparatione.conllu -O $corpus/$corpus-train.conllu
47
+
48
+ corpus=la_archimedes
49
+ echo Fetching $corpus
50
+ mkdir -p $corpus
51
+ wget https://raw.githubusercontent.com/mfantoli/ArchimedesLatinus/main/training_data_final_git.conllu -O $corpus/tmp1.conllu
52
+ wget https://raw.githubusercontent.com/mfantoli/ArchimedesLatinus/main/spirals_XIX_XX_test_git.conllu -O $corpus/tmp2.conllu
53
+ cat $corpus/tmp1.conllu $corpus/tmp2.conllu > $corpus/$corpus-train.conllu
54
+ rm $corpus/tmp1.conllu $corpus/tmp2.conllu
55
+
56
+ # Get the test data
57
+ wget https://github.com/CIRCSE/LT4HALA/raw/db51eaa114f437ac5c6cc04e802fc50cbd8b9f67/2024/data_and_doc/EvaLatin_2024_Syntactic_Parsing_test_data.zip
58
+ mkdir -p evalatin24
59
+ unzip -j EvaLatin_2024_Syntactic_Parsing_test_data.zip -d evalatin24/ -x "*/.*"
60
+ rm EvaLatin_2024_Syntactic_Parsing_test_data.zip
61
+
62
+ # Get harmonized PROIEL
63
+ mkdir -p la_proielh/
64
+ for split in train dev test; do
65
+ wget https://github.com/fjambe/Latin-variability/raw/98f676c8a4575aee24c66fee73a09aecbe515643/morpho_harmonization/morpho-harmonized-treebanks/UD_Latin-PROIEL/MM-la_proiel-ud-$split.conllu -O la_proielh/la_proielh-ud-$split.conllu
66
+ done
src/evalatin2024-latinpipe/figures/LatinPipe.svg ADDED
src/evalatin2024-latinpipe/latinpipe-evalatin24-240520/LICENSE ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Attribution-NonCommercial-ShareAlike 4.0 International
2
+
3
+ =======================================================================
4
+
5
+ Creative Commons Corporation ("Creative Commons") is not a law firm and
6
+ does not provide legal services or legal advice. Distribution of
7
+ Creative Commons public licenses does not create a lawyer-client or
8
+ other relationship. Creative Commons makes its licenses and related
9
+ information available on an "as-is" basis. Creative Commons gives no
10
+ warranties regarding its licenses, any material licensed under their
11
+ terms and conditions, or any related information. Creative Commons
12
+ disclaims all liability for damages resulting from their use to the
13
+ fullest extent possible.
14
+
15
+ Using Creative Commons Public Licenses
16
+
17
+ Creative Commons public licenses provide a standard set of terms and
18
+ conditions that creators and other rights holders may use to share
19
+ original works of authorship and other material subject to copyright
20
+ and certain other rights specified in the public license below. The
21
+ following considerations are for informational purposes only, are not
22
+ exhaustive, and do not form part of our licenses.
23
+
24
+ Considerations for licensors: Our public licenses are
25
+ intended for use by those authorized to give the public
26
+ permission to use material in ways otherwise restricted by
27
+ copyright and certain other rights. Our licenses are
28
+ irrevocable. Licensors should read and understand the terms
29
+ and conditions of the license they choose before applying it.
30
+ Licensors should also secure all rights necessary before
31
+ applying our licenses so that the public can reuse the
32
+ material as expected. Licensors should clearly mark any
33
+ material not subject to the license. This includes other CC-
34
+ licensed material, or material used under an exception or
35
+ limitation to copyright. More considerations for licensors:
36
+ wiki.creativecommons.org/Considerations_for_licensors
37
+
38
+ Considerations for the public: By using one of our public
39
+ licenses, a licensor grants the public permission to use the
40
+ licensed material under specified terms and conditions. If
41
+ the licensor's permission is not necessary for any reason--for
42
+ example, because of any applicable exception or limitation to
43
+ copyright--then that use is not regulated by the license. Our
44
+ licenses grant only permissions under copyright and certain
45
+ other rights that a licensor has authority to grant. Use of
46
+ the licensed material may still be restricted for other
47
+ reasons, including because others have copyright or other
48
+ rights in the material. A licensor may make special requests,
49
+ such as asking that all changes be marked or described.
50
+ Although not required by our licenses, you are encouraged to
51
+ respect those requests where reasonable. More_considerations
52
+ for the public:
53
+ wiki.creativecommons.org/Considerations_for_licensees
54
+
55
+ =======================================================================
56
+
57
+ Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International
58
+ Public License
59
+
60
+ By exercising the Licensed Rights (defined below), You accept and agree
61
+ to be bound by the terms and conditions of this Creative Commons
62
+ Attribution-NonCommercial-ShareAlike 4.0 International Public License
63
+ ("Public License"). To the extent this Public License may be
64
+ interpreted as a contract, You are granted the Licensed Rights in
65
+ consideration of Your acceptance of these terms and conditions, and the
66
+ Licensor grants You such rights in consideration of benefits the
67
+ Licensor receives from making the Licensed Material available under
68
+ these terms and conditions.
69
+
70
+
71
+ Section 1 -- Definitions.
72
+
73
+ a. Adapted Material means material subject to Copyright and Similar
74
+ Rights that is derived from or based upon the Licensed Material
75
+ and in which the Licensed Material is translated, altered,
76
+ arranged, transformed, or otherwise modified in a manner requiring
77
+ permission under the Copyright and Similar Rights held by the
78
+ Licensor. For purposes of this Public License, where the Licensed
79
+ Material is a musical work, performance, or sound recording,
80
+ Adapted Material is always produced where the Licensed Material is
81
+ synched in timed relation with a moving image.
82
+
83
+ b. Adapter's License means the license You apply to Your Copyright
84
+ and Similar Rights in Your contributions to Adapted Material in
85
+ accordance with the terms and conditions of this Public License.
86
+
87
+ c. BY-NC-SA Compatible License means a license listed at
88
+ creativecommons.org/compatiblelicenses, approved by Creative
89
+ Commons as essentially the equivalent of this Public License.
90
+
91
+ d. Copyright and Similar Rights means copyright and/or similar rights
92
+ closely related to copyright including, without limitation,
93
+ performance, broadcast, sound recording, and Sui Generis Database
94
+ Rights, without regard to how the rights are labeled or
95
+ categorized. For purposes of this Public License, the rights
96
+ specified in Section 2(b)(1)-(2) are not Copyright and Similar
97
+ Rights.
98
+
99
+ e. Effective Technological Measures means those measures that, in the
100
+ absence of proper authority, may not be circumvented under laws
101
+ fulfilling obligations under Article 11 of the WIPO Copyright
102
+ Treaty adopted on December 20, 1996, and/or similar international
103
+ agreements.
104
+
105
+ f. Exceptions and Limitations means fair use, fair dealing, and/or
106
+ any other exception or limitation to Copyright and Similar Rights
107
+ that applies to Your use of the Licensed Material.
108
+
109
+ g. License Elements means the license attributes listed in the name
110
+ of a Creative Commons Public License. The License Elements of this
111
+ Public License are Attribution, NonCommercial, and ShareAlike.
112
+
113
+ h. Licensed Material means the artistic or literary work, database,
114
+ or other material to which the Licensor applied this Public
115
+ License.
116
+
117
+ i. Licensed Rights means the rights granted to You subject to the
118
+ terms and conditions of this Public License, which are limited to
119
+ all Copyright and Similar Rights that apply to Your use of the
120
+ Licensed Material and that the Licensor has authority to license.
121
+
122
+ j. Licensor means the individual(s) or entity(ies) granting rights
123
+ under this Public License.
124
+
125
+ k. NonCommercial means not primarily intended for or directed towards
126
+ commercial advantage or monetary compensation. For purposes of
127
+ this Public License, the exchange of the Licensed Material for
128
+ other material subject to Copyright and Similar Rights by digital
129
+ file-sharing or similar means is NonCommercial provided there is
130
+ no payment of monetary compensation in connection with the
131
+ exchange.
132
+
133
+ l. Share means to provide material to the public by any means or
134
+ process that requires permission under the Licensed Rights, such
135
+ as reproduction, public display, public performance, distribution,
136
+ dissemination, communication, or importation, and to make material
137
+ available to the public including in ways that members of the
138
+ public may access the material from a place and at a time
139
+ individually chosen by them.
140
+
141
+ m. Sui Generis Database Rights means rights other than copyright
142
+ resulting from Directive 96/9/EC of the European Parliament and of
143
+ the Council of 11 March 1996 on the legal protection of databases,
144
+ as amended and/or succeeded, as well as other essentially
145
+ equivalent rights anywhere in the world.
146
+
147
+ n. You means the individual or entity exercising the Licensed Rights
148
+ under this Public License. Your has a corresponding meaning.
149
+
150
+
151
+ Section 2 -- Scope.
152
+
153
+ a. License grant.
154
+
155
+ 1. Subject to the terms and conditions of this Public License,
156
+ the Licensor hereby grants You a worldwide, royalty-free,
157
+ non-sublicensable, non-exclusive, irrevocable license to
158
+ exercise the Licensed Rights in the Licensed Material to:
159
+
160
+ a. reproduce and Share the Licensed Material, in whole or
161
+ in part, for NonCommercial purposes only; and
162
+
163
+ b. produce, reproduce, and Share Adapted Material for
164
+ NonCommercial purposes only.
165
+
166
+ 2. Exceptions and Limitations. For the avoidance of doubt, where
167
+ Exceptions and Limitations apply to Your use, this Public
168
+ License does not apply, and You do not need to comply with
169
+ its terms and conditions.
170
+
171
+ 3. Term. The term of this Public License is specified in Section
172
+ 6(a).
173
+
174
+ 4. Media and formats; technical modifications allowed. The
175
+ Licensor authorizes You to exercise the Licensed Rights in
176
+ all media and formats whether now known or hereafter created,
177
+ and to make technical modifications necessary to do so. The
178
+ Licensor waives and/or agrees not to assert any right or
179
+ authority to forbid You from making technical modifications
180
+ necessary to exercise the Licensed Rights, including
181
+ technical modifications necessary to circumvent Effective
182
+ Technological Measures. For purposes of this Public License,
183
+ simply making modifications authorized by this Section 2(a)
184
+ (4) never produces Adapted Material.
185
+
186
+ 5. Downstream recipients.
187
+
188
+ a. Offer from the Licensor -- Licensed Material. Every
189
+ recipient of the Licensed Material automatically
190
+ receives an offer from the Licensor to exercise the
191
+ Licensed Rights under the terms and conditions of this
192
+ Public License.
193
+
194
+ b. Additional offer from the Licensor -- Adapted Material.
195
+ Every recipient of Adapted Material from You
196
+ automatically receives an offer from the Licensor to
197
+ exercise the Licensed Rights in the Adapted Material
198
+ under the conditions of the Adapter's License You apply.
199
+
200
+ c. No downstream restrictions. You may not offer or impose
201
+ any additional or different terms or conditions on, or
202
+ apply any Effective Technological Measures to, the
203
+ Licensed Material if doing so restricts exercise of the
204
+ Licensed Rights by any recipient of the Licensed
205
+ Material.
206
+
207
+ 6. No endorsement. Nothing in this Public License constitutes or
208
+ may be construed as permission to assert or imply that You
209
+ are, or that Your use of the Licensed Material is, connected
210
+ with, or sponsored, endorsed, or granted official status by,
211
+ the Licensor or others designated to receive attribution as
212
+ provided in Section 3(a)(1)(A)(i).
213
+
214
+ b. Other rights.
215
+
216
+ 1. Moral rights, such as the right of integrity, are not
217
+ licensed under this Public License, nor are publicity,
218
+ privacy, and/or other similar personality rights; however, to
219
+ the extent possible, the Licensor waives and/or agrees not to
220
+ assert any such rights held by the Licensor to the limited
221
+ extent necessary to allow You to exercise the Licensed
222
+ Rights, but not otherwise.
223
+
224
+ 2. Patent and trademark rights are not licensed under this
225
+ Public License.
226
+
227
+ 3. To the extent possible, the Licensor waives any right to
228
+ collect royalties from You for the exercise of the Licensed
229
+ Rights, whether directly or through a collecting society
230
+ under any voluntary or waivable statutory or compulsory
231
+ licensing scheme. In all other cases the Licensor expressly
232
+ reserves any right to collect such royalties, including when
233
+ the Licensed Material is used other than for NonCommercial
234
+ purposes.
235
+
236
+
237
+ Section 3 -- License Conditions.
238
+
239
+ Your exercise of the Licensed Rights is expressly made subject to the
240
+ following conditions.
241
+
242
+ a. Attribution.
243
+
244
+ 1. If You Share the Licensed Material (including in modified
245
+ form), You must:
246
+
247
+ a. retain the following if it is supplied by the Licensor
248
+ with the Licensed Material:
249
+
250
+ i. identification of the creator(s) of the Licensed
251
+ Material and any others designated to receive
252
+ attribution, in any reasonable manner requested by
253
+ the Licensor (including by pseudonym if
254
+ designated);
255
+
256
+ ii. a copyright notice;
257
+
258
+ iii. a notice that refers to this Public License;
259
+
260
+ iv. a notice that refers to the disclaimer of
261
+ warranties;
262
+
263
+ v. a URI or hyperlink to the Licensed Material to the
264
+ extent reasonably practicable;
265
+
266
+ b. indicate if You modified the Licensed Material and
267
+ retain an indication of any previous modifications; and
268
+
269
+ c. indicate the Licensed Material is licensed under this
270
+ Public License, and include the text of, or the URI or
271
+ hyperlink to, this Public License.
272
+
273
+ 2. You may satisfy the conditions in Section 3(a)(1) in any
274
+ reasonable manner based on the medium, means, and context in
275
+ which You Share the Licensed Material. For example, it may be
276
+ reasonable to satisfy the conditions by providing a URI or
277
+ hyperlink to a resource that includes the required
278
+ information.
279
+ 3. If requested by the Licensor, You must remove any of the
280
+ information required by Section 3(a)(1)(A) to the extent
281
+ reasonably practicable.
282
+
283
+ b. ShareAlike.
284
+
285
+ In addition to the conditions in Section 3(a), if You Share
286
+ Adapted Material You produce, the following conditions also apply.
287
+
288
+ 1. The Adapter's License You apply must be a Creative Commons
289
+ license with the same License Elements, this version or
290
+ later, or a BY-NC-SA Compatible License.
291
+
292
+ 2. You must include the text of, or the URI or hyperlink to, the
293
+ Adapter's License You apply. You may satisfy this condition
294
+ in any reasonable manner based on the medium, means, and
295
+ context in which You Share Adapted Material.
296
+
297
+ 3. You may not offer or impose any additional or different terms
298
+ or conditions on, or apply any Effective Technological
299
+ Measures to, Adapted Material that restrict exercise of the
300
+ rights granted under the Adapter's License You apply.
301
+
302
+
303
+ Section 4 -- Sui Generis Database Rights.
304
+
305
+ Where the Licensed Rights include Sui Generis Database Rights that
306
+ apply to Your use of the Licensed Material:
307
+
308
+ a. for the avoidance of doubt, Section 2(a)(1) grants You the right
309
+ to extract, reuse, reproduce, and Share all or a substantial
310
+ portion of the contents of the database for NonCommercial purposes
311
+ only;
312
+
313
+ b. if You include all or a substantial portion of the database
314
+ contents in a database in which You have Sui Generis Database
315
+ Rights, then the database in which You have Sui Generis Database
316
+ Rights (but not its individual contents) is Adapted Material,
317
+ including for purposes of Section 3(b); and
318
+
319
+ c. You must comply with the conditions in Section 3(a) if You Share
320
+ all or a substantial portion of the contents of the database.
321
+
322
+ For the avoidance of doubt, this Section 4 supplements and does not
323
+ replace Your obligations under this Public License where the Licensed
324
+ Rights include other Copyright and Similar Rights.
325
+
326
+
327
+ Section 5 -- Disclaimer of Warranties and Limitation of Liability.
328
+
329
+ a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE
330
+ EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS
331
+ AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF
332
+ ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,
333
+ IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,
334
+ WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR
335
+ PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,
336
+ ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT
337
+ KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT
338
+ ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.
339
+
340
+ b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE
341
+ TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,
342
+ NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,
343
+ INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,
344
+ COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR
345
+ USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN
346
+ ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR
347
+ DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR
348
+ IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.
349
+
350
+ c. The disclaimer of warranties and limitation of liability provided
351
+ above shall be interpreted in a manner that, to the extent
352
+ possible, most closely approximates an absolute disclaimer and
353
+ waiver of all liability.
354
+
355
+
356
+ Section 6 -- Term and Termination.
357
+
358
+ a. This Public License applies for the term of the Copyright and
359
+ Similar Rights licensed here. However, if You fail to comply with
360
+ this Public License, then Your rights under this Public License
361
+ terminate automatically.
362
+
363
+ b. Where Your right to use the Licensed Material has terminated under
364
+ Section 6(a), it reinstates:
365
+
366
+ 1. automatically as of the date the violation is cured, provided
367
+ it is cured within 30 days of Your discovery of the
368
+ violation; or
369
+
370
+ 2. upon express reinstatement by the Licensor.
371
+
372
+ For the avoidance of doubt, this Section 6(b) does not affect any
373
+ right the Licensor may have to seek remedies for Your violations
374
+ of this Public License.
375
+
376
+ c. For the avoidance of doubt, the Licensor may also offer the
377
+ Licensed Material under separate terms or conditions or stop
378
+ distributing the Licensed Material at any time; however, doing so
379
+ will not terminate this Public License.
380
+
381
+ d. Sections 1, 5, 6, 7, and 8 survive termination of this Public
382
+ License.
383
+
384
+
385
+ Section 7 -- Other Terms and Conditions.
386
+
387
+ a. The Licensor shall not be bound by any additional or different
388
+ terms or conditions communicated by You unless expressly agreed.
389
+
390
+ b. Any arrangements, understandings, or agreements regarding the
391
+ Licensed Material not stated herein are separate from and
392
+ independent of the terms and conditions of this Public License.
393
+
394
+
395
+ Section 8 -- Interpretation.
396
+
397
+ a. For the avoidance of doubt, this Public License does not, and
398
+ shall not be interpreted to, reduce, limit, restrict, or impose
399
+ conditions on any use of the Licensed Material that could lawfully
400
+ be made without permission under this Public License.
401
+
402
+ b. To the extent possible, if any provision of this Public License is
403
+ deemed unenforceable, it shall be automatically reformed to the
404
+ minimum extent necessary to make it enforceable. If the provision
405
+ cannot be reformed, it shall be severed from this Public License
406
+ without affecting the enforceability of the remaining terms and
407
+ conditions.
408
+
409
+ c. No term or condition of this Public License will be waived and no
410
+ failure to comply consented to unless expressly agreed to by the
411
+ Licensor.
412
+
413
+ d. Nothing in this Public License constitutes or may be interpreted
414
+ as a limitation upon, or waiver of, any privileges and immunities
415
+ that apply to the Licensor or You, including from the legal
416
+ processes of any jurisdiction or authority.
417
+
418
+ =======================================================================
419
+
420
+ Creative Commons is not a party to its public licenses.
421
+ Notwithstanding, Creative Commons may elect to apply one of its public
422
+ licenses to material it publishes and in those instances will be
423
+ considered the "Licensor." Except for the limited purpose of indicating
424
+ that material is shared under a Creative Commons public license or as
425
+ otherwise permitted by the Creative Commons policies published at
426
+ creativecommons.org/policies, Creative Commons does not authorize the
427
+ use of the trademark "Creative Commons" or any other trademark or logo
428
+ of Creative Commons without its prior written consent including,
429
+ without limitation, in connection with any unauthorized modifications
430
+ to any of its public licenses or any other arrangements,
431
+ understandings, or agreements concerning use of licensed material. For
432
+ the avoidance of doubt, this paragraph does not form part of the public
433
+ licenses.
434
+
435
+ Creative Commons may be contacted at creativecommons.org.
src/evalatin2024-latinpipe/latinpipe-evalatin24-240520/README.md ADDED
@@ -0,0 +1,71 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # The `latinpipe-evalatin24-240520` Model
2
+
3
+ The `latinpipe-evalatin24-240520` is a `PhilBerta`-based model for tagging,
4
+ lemmatization, and dependency parsing of Latin, based on the winning entry
5
+ to the EvaLatin 2024 <https://circse.github.io/LT4HALA/2024/EvaLatin> shared
6
+ task. It is released at https://hdl.handle.net/11234/1-5671 under the CC
7
+ BY-NC-SA 4.0 license.
8
+
9
+ The model is also available in the [UDPipe LINDAT/CLARIN service](http://lindat.mff.cuni.cz/services/udpipe/)
10
+ and can be used either in a web form or through a REST service.
11
+
12
+ The model was trained using the following command:
13
+ ```sh
14
+ la_ud213_all="la_ittb la_llct la_perseus la_proiel la_udante"
15
+ la_other="la_archimedes la_sabellicus"
16
+ transformer="bowphs/PhilBerta" # or bowphs/LaBerta
17
+
18
+ latinpipe_evalatin24.py $(for split in dev test train; do echo --$split; for tb in $la_ud213_all; do [ $tb-$split = la_proiel-train ] && tb=la_proielh; echo data/$tb/$tb-ud-$split.conllu; done; done) $(for tb in $la_other; do echo data/$tb/$tb-train.conllu; done) --transformers $transformer --epochs=30 --exp=latinpipe-evalatin24-240520 --subword_combination=last --epochs_frozen=10 --batch_size=64 --save_checkpoint
19
+ ```
20
+
21
+ ## EvaLatin 2024 LAS Results
22
+
23
+ The model achieves the following EvaLatin 2024 results (measured by the
24
+ official scorer). Note that the results are worse than in the paper, where the
25
+ model used the gold POS tags and was ensembled.
26
+
27
+ Treebank | UAS | LAS |
28
+ :-------------------- |:-----:|:-----:|
29
+ EvaLatin 2024 Poetry | 78.31 | 72.36 |
30
+ EvaLatin 2024 Prose | 80.49 | 75.20 |
31
+ EvaLatin 2024 Average | 79.40 | 73.78 |
32
+
33
+ ## UD 2.13 Results
34
+
35
+ The model achieves the following UPOS, UFeats, Lemmas, UAS, LAS metrics (as
36
+ measured by the official scorer) on the UD 2.13 test data. Note that the model
37
+ was trained on harmonized PROIEL, so we do not include the official PROIEL
38
+ treebank in the evaluation.
39
+
40
+ Treebank | UPOS | UFeats | Lemmas | UAS | LAS |
41
+ :--------|:-----:|:------:|:------:|:-----:|:-----:|
42
+ ITTB | 99.30 | 98.53 | 98.64 | 93.82 | 92.31 |
43
+ LLCT | 99.80 | 97.60 | 96.39 | 96.37 | 95.35 |
44
+ Perseus | 96.01 | 91.14 | 88.88 | 87.93 | 82.50 |
45
+ UDante | 93.73 | 89.27 | 87.76 | 83.97 | 78.67 |
46
+
47
+ ## Predicting with the `latinpipe-evalatin24-240520` Model
48
+
49
+ To predict with the `latinpipe-evalatin24-240520` model, you can use the following command:
50
+ ```sh
51
+ latinpipe_evalatin24.py --load latinpipe-evalatin24-240520/model.weights.h5 --exp target_directory --test input1.conllu input2.conllu
52
+ ```
53
+ - the outputs are generated in the target directory, with a `.predicted.conllu` suffix;
54
+ - if you want to also evaluate the predicted files, you can use `--dev` option instead of `--test`.
55
+
56
+ ## How to Cite
57
+
58
+ ```
59
+ @inproceedings{straka-etal-2024-ufal,
60
+ title = "{{\'U}FAL} {L}atin{P}ipe at {E}va{L}atin 2024: Morphosyntactic Analysis of {L}atin",
61
+ author = "Straka, Milan and Strakov{\'a}, Jana and Gamba, Federica",
62
+ editor = "Sprugnoli, Rachele and Passarotti, Marco",
63
+ booktitle = "Proceedings of the Third Workshop on Language Technologies for Historical and Ancient Languages (LT4HALA) @ LREC-COLING-2024",
64
+ month = may,
65
+ year = "2024",
66
+ address = "Torino, Italia",
67
+ publisher = "ELRA and ICCL",
68
+ url = "https://aclanthology.org/2024.lt4hala-1.24",
69
+ pages = "207--214"
70
+ }
71
+ ```
src/evalatin2024-latinpipe/latinpipe_evalatin24.py ADDED
@@ -0,0 +1,944 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ #
3
+ # This file is part of LatinPipe EvaLatin 24
4
+ # <https://github.com/ufal/evalatin2024-latinpipe>.
5
+ #
6
+ # Copyright 2024 Institute of Formal and Applied Linguistics, Faculty of
7
+ # Mathematics and Physics, Charles University in Prague, Czech Republic.
8
+ #
9
+ # This Source Code Form is subject to the terms of the Mozilla Public
10
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
11
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
+
13
+ import argparse
14
+ import collections
15
+ import datetime
16
+ import difflib
17
+ import io
18
+ import json
19
+ import os
20
+ import pickle
21
+ import re
22
+ from typing import Self
23
+ os.environ.setdefault("KERAS_BACKEND", "torch")
24
+
25
+ import keras
26
+ import numpy as np
27
+ import torch
28
+ import transformers
29
+ import ufal.chu_liu_edmonds
30
+
31
+ import latinpipe_evalatin24_eval
32
+
33
+ parser = argparse.ArgumentParser()
34
+ parser.add_argument("--batch_size", default=32, type=int, help="Batch size.")
35
+ parser.add_argument("--deprel", default="full", choices=["full", "universal"], type=str, help="Deprel kind.")
36
+ parser.add_argument("--dev", default=[], nargs="+", type=str, help="Dev CoNLL-U files.")
37
+ parser.add_argument("--dropout", default=0.5, type=float, help="Dropout")
38
+ parser.add_argument("--embed_tags", default="", type=str, help="Tags to embed on input.")
39
+ parser.add_argument("--epochs", default=30, type=int, help="Number of epochs.")
40
+ parser.add_argument("--epochs_frozen", default=0, type=int, help="Number of epochs with frozen transformer.")
41
+ parser.add_argument("--exp", default=None, type=str, help="Experiment name.")
42
+ parser.add_argument("--label_smoothing", default=0.03, type=float, help="Label smoothing.")
43
+ parser.add_argument("--learning_rate", default=2e-5, type=float, help="Learning rate.")
44
+ parser.add_argument("--learning_rate_decay", default="cos", choices=["none", "cos"], type=str, help="Learning rate decay.")
45
+ parser.add_argument("--learning_rate_warmup", default=2_000, type=int, help="Number of warmup steps.")
46
+ parser.add_argument("--load", default=[], type=str, nargs="*", help="Path to load models from.")
47
+ parser.add_argument("--max_train_sentence_len", default=150, type=int, help="Max sentence subwords in training.")
48
+ parser.add_argument("--optimizer", default="adam", choices=["adam", "adafactor"], type=str, help="Optimizer.")
49
+ parser.add_argument("--parse", default=1, type=int, help="Parse.")
50
+ parser.add_argument("--parse_attention_dim", default=512, type=int, help="Parse attention dimension.")
51
+ parser.add_argument("--rnn_dim", default=512, type=int, help="RNN layers size.")
52
+ parser.add_argument("--rnn_layers", default=2, type=int, help="RNN layers.")
53
+ parser.add_argument("--rnn_type", default="LSTMTorch", choices=["LSTM", "GRU", "LSTMTorch", "GRUTorch"], help="RNN type.")
54
+ parser.add_argument("--save_checkpoint", default=False, action="store_true", help="Save checkpoint.")
55
+ parser.add_argument("--seed", default=42, type=int, help="Initial random seed.")
56
+ parser.add_argument("--steps_per_epoch", default=1_000, type=int, help="Steps per epoch.")
57
+ parser.add_argument("--single_root", default=1, type=int, help="Single root allowed only.")
58
+ parser.add_argument("--subword_combination", default="first", choices=["first", "last", "sum", "concat"], type=str, help="Subword combination.")
59
+ parser.add_argument("--tags", default="UPOS,LEMMAS,FEATS", type=str, help="Tags to predict.")
60
+ parser.add_argument("--task_hidden_layer", default=2_048, type=int, help="Task hidden layer size.")
61
+ parser.add_argument("--test", default=[], nargs="+", type=str, help="Test CoNLL-U files.")
62
+ parser.add_argument("--train", default=[], nargs="+", type=str, help="Train CoNLL-U files.")
63
+ parser.add_argument("--train_sampling_exponent", default=0.5, type=float, help="Train sampling exponent.")
64
+ parser.add_argument("--transformers", nargs="+", type=str, help="Transformers models to use.")
65
+ parser.add_argument("--treebank_ids", default=False, action="store_true", help="Include treebank IDs on input.")
66
+ parser.add_argument("--threads", default=4, type=int, help="Maximum number of threads to use.")
67
+ parser.add_argument("--verbose", default=2, type=int, help="Verbosity")
68
+ parser.add_argument("--wandb", default=False, action="store_true", help="Log in WandB.")
69
+ parser.add_argument("--word_masking", default=None, type=float, help="Word masking")
70
+
71
+ os.environ["PYTORCH_MPS_HIGH_WATERMARK_RATIO"] = "0.0"
72
+
73
+ class UDDataset:
74
+ FORMS, LEMMAS, UPOS, XPOS, FEATS, HEAD, DEPREL, DEPS, MISC, FACTORS = range(10)
75
+ FACTORS_MAP = {"FORMS": FORMS, "LEMMAS": LEMMAS, "UPOS": UPOS, "XPOS": XPOS, "FEATS": FEATS,
76
+ "HEAD": HEAD, "DEPREL": DEPREL, "DEPS": DEPS, "MISC": MISC}
77
+ RE_EXTRAS = re.compile(r"^#|^\d+-|^\d+\.")
78
+
79
+ class Factor:
80
+ def __init__(self, train_factor: Self = None):
81
+ self.words_map = train_factor.words_map if train_factor else {"<unk>": 0}
82
+ self.words = train_factor.words if train_factor else ["<unk>"]
83
+ self.word_ids = []
84
+ self.strings = []
85
+
86
+ def __init__(self, path: str, args: argparse.Namespace, treebank_id: int|None = None, train_dataset: Self = None, text: str|None = None):
87
+ self.path = path
88
+
89
+ # Create factors and other variables
90
+ self.factors = []
91
+ for f in range(self.FACTORS):
92
+ self.factors.append(self.Factor(train_dataset.factors[f] if train_dataset is not None else None))
93
+ self._extras = []
94
+
95
+ lemma_transforms = collections.Counter()
96
+
97
+ # Load the CoNLL-U file
98
+ with open(path, "r", encoding="utf-8") if text is None else io.StringIO(text) as file:
99
+ in_sentence = False
100
+ for line in file:
101
+ line = line.rstrip("\r\n")
102
+
103
+ if line:
104
+ if self.RE_EXTRAS.match(line):
105
+ if in_sentence:
106
+ while len(self._extras) < len(self.factors[0].strings): self._extras.append([])
107
+ while len(self._extras[-1]) <= len(self.factors[0].strings[-1]):
108
+ self._extras[-1].append("")
109
+ else:
110
+ while len(self._extras) <= len(self.factors[0].strings): self._extras.append([])
111
+ if not len(self._extras[-1]): self._extras[-1].append("")
112
+ self._extras[-1][-1] += ("\n" if self._extras[-1][-1] else "") + line
113
+ continue
114
+
115
+ columns = line.split("\t")[1:]
116
+ for f in range(self.FACTORS):
117
+ factor = self.factors[f]
118
+ if not in_sentence:
119
+ factor.word_ids.append([])
120
+ factor.strings.append([])
121
+
122
+ word = columns[f]
123
+ factor.strings[-1].append(word)
124
+
125
+ # Add word to word_ids
126
+ if f == self.FORMS:
127
+ # For formw, we do not remap strings into IDs because the tokenizer will create the subwords IDs for us.
128
+ factor.word_ids[-1].append(0)
129
+ elif f == self.HEAD:
130
+ factor.word_ids[-1].append(int(word) if word != "_" else -1)
131
+ elif f == self.LEMMAS:
132
+ factor.word_ids[-1].append(0)
133
+ lemma_transforms[(columns[self.FORMS], word)] += 1
134
+ else:
135
+ if f == self.DEPREL and args.deprel == "universal":
136
+ word = word.split(":")[0]
137
+ if word not in factor.words_map:
138
+ if train_dataset is not None:
139
+ word = "<unk>"
140
+ else:
141
+ factor.words_map[word] = len(factor.words)
142
+ factor.words.append(word)
143
+ factor.word_ids[-1].append(factor.words_map[word])
144
+ in_sentence = True
145
+ else:
146
+ in_sentence = False
147
+ for factor in self.factors:
148
+ if len(factor.word_ids): factor.word_ids[-1] = np.array(factor.word_ids[-1], np.int32)
149
+
150
+ # Also load the file for evaluation if it is not a training dataset
151
+ if train_dataset is not None:
152
+ file.seek(0, io.SEEK_SET)
153
+ self.conllu_for_eval = latinpipe_evalatin24_eval.load_conllu(file)
154
+
155
+ # Construct lemma rules
156
+ self.finalize_lemma_rules(lemma_transforms, create_rules=train_dataset is None)
157
+
158
+ # The dataset consists of a single treebank
159
+ self.treebank_ranges = [(0, len(self))]
160
+ self.treebank_ids = [treebank_id]
161
+
162
+ # Create an empty tokenize cache
163
+ self._tokenizer_cache = {}
164
+
165
+ def __len__(self):
166
+ return len(self.factors[0].strings)
167
+
168
+ def save_mappings(self, path: str) -> None:
169
+ mappings = UDDataset.__new__(UDDataset)
170
+ mappings.factors = []
171
+ for factor in self.factors:
172
+ mappings.factors.append(UDDataset.Factor.__new__(UDDataset.Factor))
173
+ mappings.factors[-1].words = factor.words
174
+ with open(path, "wb") as mappings_file:
175
+ pickle.dump(mappings, mappings_file, protocol=4)
176
+
177
+ @staticmethod
178
+ def from_mappings(path: str) -> Self:
179
+ with open(path, "rb") as mappings_file:
180
+ mappings = pickle.load(mappings_file)
181
+ for factor in mappings.factors:
182
+ factor.words_map = {word: i for i, word in enumerate(factor.words)}
183
+ return mappings
184
+
185
+ @staticmethod
186
+ def create_lemma_rule(form: str, lemma: str) -> str:
187
+ diff = difflib.SequenceMatcher(None, form.lower(), lemma.lower(), False)
188
+ rule, in_prefix = [], True
189
+ for tag, i1, i2, j1, j2 in diff.get_opcodes():
190
+ if i2 > len(form) // 3 and in_prefix:
191
+ in_prefix = False
192
+ if tag == "equal":
193
+ mode, jd = "L" if lemma[j2 - 1].islower() else "U", j2 - 1
194
+ while jd > j1 and lemma[jd - 1].islower() == lemma[j2 - 1].islower(): jd -= 1
195
+ rule.extend(["l" if lemma[j].islower() else "u" for j in range(j1, jd)])
196
+ rule.extend(mode * (len(form) - i2 + 1))
197
+ if tag in ["replace", "delete"]:
198
+ rule.extend("D" * (len(form) - i2 + 1))
199
+ if tag in ["replace", "insert"]:
200
+ rule.extend("i" + lemma[j] for j in range(j1, j2))
201
+ else:
202
+ if tag == "equal":
203
+ rule.extend(["l" if lemma[j].islower() else "u" for j in range(j1, j2)])
204
+ if tag in ["replace", "delete"]:
205
+ rule.extend("d" * (i2 - i1))
206
+ if tag in ["replace", "insert"]:
207
+ rule.extend("i" + lemma[j] for j in range(j1, j2))
208
+ return "".join(rule)
209
+
210
+ @staticmethod
211
+ def apply_lemma_rule(rule: str, form: str) -> str:
212
+ def error():
213
+ # print("Error: cannot decode lemma rule '{}' with form '{}', copying input.".format(rule, form))
214
+ return form
215
+
216
+ if rule == "<unk>":
217
+ return form
218
+
219
+ lemma, r, i = [], 0, 0
220
+ while r < len(rule):
221
+ if rule[r] == "i":
222
+ if r + 1 == len(rule):
223
+ return error()
224
+ r += 1
225
+ lemma.append(rule[r])
226
+ elif rule[r] == "d":
227
+ i += 1
228
+ elif rule[r] in ("l", "u"):
229
+ if i == len(form):
230
+ return error()
231
+ lemma.append(form[i].lower() if rule[r] == "l" else form[i].upper())
232
+ i += 1
233
+ elif rule[r] in ("L", "U", "D"):
234
+ i2 = len(form)
235
+ while r + 1 < len(rule) and rule[r + 1] == rule[r]:
236
+ r += 1
237
+ i2 -= 1
238
+ if i2 < i:
239
+ return error()
240
+ if rule[r] == "L":
241
+ lemma.extend(form[i:i2].lower())
242
+ if rule[r] == "U":
243
+ lemma.extend(form[i:i2].upper())
244
+ i = i2
245
+ else:
246
+ return error()
247
+ r += 1
248
+ if i != len(form) or not lemma:
249
+ return error()
250
+ return "".join(lemma)
251
+
252
+ def finalize_lemma_rules(self, lemma_transforms: collections.Counter, create_rules: bool) -> None:
253
+ forms, lemmas = self.factors[self.FORMS], self.factors[self.LEMMAS]
254
+
255
+ # Generate all rules
256
+ rules_merged, rules_all = collections.Counter(), {}
257
+ for form, lemma in lemma_transforms:
258
+ rule = self.create_lemma_rule(form, lemma)
259
+ rules_all[(form, lemma)] = rule
260
+ if create_rules:
261
+ rules_merged[rule] += 1
262
+
263
+ # Keep the rules that are used more than once
264
+ if create_rules:
265
+ for rule, count in rules_merged.items():
266
+ if count > 1:
267
+ lemmas.words_map[rule] = len(lemmas.words)
268
+ lemmas.words.append(rule)
269
+
270
+ # Store the rules in the dataset
271
+ for i in range(len(forms.strings)):
272
+ for j in range(len(forms.strings[i])):
273
+ rule = rules_all.get((forms.strings[i][j], lemmas.strings[i][j]))
274
+ lemmas.word_ids[i][j] = lemmas.words_map.get(rule, 0)
275
+
276
+ def tokenize(self, tokenizer: transformers.PreTrainedTokenizer) -> tuple[list[np.ndarray], list[np.ndarray]]:
277
+ if tokenizer not in self._tokenizer_cache:
278
+ assert tokenizer.cls_token_id is not None, "The tokenizer must have a CLS token"
279
+
280
+ tokenized = tokenizer(self.factors[0].strings, add_special_tokens=True, is_split_into_words=True)
281
+
282
+ tokens, word_indices = [], []
283
+ for i, sentence in enumerate(tokenized.input_ids):
284
+ offset = 0
285
+ if not len(sentence) or sentence[0] != tokenizer.cls_token_id:
286
+ # Handle tokenizers that do not add CLS tokens, which we need for prediction
287
+ # of the root nodes during parsing. For such tokenizers, we added the CLS token
288
+ # manually already, but the build_inputs_with_special_tokens() might not have added it.
289
+ sentence = [tokenizer.cls_token_id] + sentence
290
+ offset = 1
291
+
292
+ treebank_id = None
293
+ for id_, (start, end) in zip(self.treebank_ids, self.treebank_ranges):
294
+ if start <= i < end:
295
+ treebank_id = id_
296
+ if treebank_id is not None:
297
+ sentence.insert(1, tokenizer.additional_special_tokens_ids[treebank_id])
298
+ offset += 1
299
+
300
+ tokens.append(np.array(sentence, dtype=np.int32))
301
+ word_indices.append([(0, 0)])
302
+ for j in range(len(self.factors[0].strings[i])):
303
+ span = tokenized.word_to_tokens(i, j)
304
+ if (span == None):
305
+ print("-x-x-x-", i, j)
306
+ try:
307
+ word_indices[-1].append((offset + span.start, offset + span.end - 1))
308
+ except:
309
+ #abracadabra = 0
310
+ print(treebank_id)
311
+ input("??")
312
+ word_indices[-1] = np.array(word_indices[-1], dtype=np.int32)
313
+
314
+
315
+ self._tokenizer_cache[tokenizer] = (tokens, word_indices)
316
+
317
+ return self._tokenizer_cache[tokenizer]
318
+
319
+ def write_sentence(self, output: io.TextIOBase, index: int, overrides: list = None) -> None:
320
+ assert index < len(self.factors[0].strings), "Sentence index out of range"
321
+
322
+ for i in range(len(self.factors[0].strings[index]) + 1):
323
+ # Start by writing extras
324
+ if index < len(self._extras) and i < len(self._extras[index]) and self._extras[index][i]:
325
+ print(self._extras[index][i], file=output)
326
+ if i == len(self.factors[0].strings[index]): break
327
+
328
+ fields = []
329
+ fields.append(str(i + 1))
330
+ for f in range(self.FACTORS):
331
+ factor = self.factors[f]
332
+ field = factor.strings[index][i]
333
+
334
+ # Overrides
335
+ if overrides is not None and f < len(overrides) and overrides[f] is not None:
336
+ override = overrides[f][i]
337
+ if f == self.HEAD:
338
+ field = str(override) if override >= 0 else "_"
339
+ else:
340
+ field = factor.words[override]
341
+ if f == self.LEMMAS:
342
+ field = self.apply_lemma_rule(field, self.factors[self.FORMS].strings[index][i])
343
+ fields.append(field)
344
+
345
+ print("\t".join(fields), file=output)
346
+ print(file=output)
347
+
348
+
349
+ class UDDatasetMerged(UDDataset):
350
+ def __init__(self, datasets: list[UDDataset]):
351
+ # Create factors and other variables
352
+ self.factors = []
353
+ for f in range(self.FACTORS):
354
+ self.factors.append(self.Factor(None))
355
+
356
+ lemma_transforms = collections.Counter()
357
+
358
+ self.treebank_ranges, self.treebank_ids = [], []
359
+ for dataset in datasets:
360
+ assert len(dataset.treebank_ranges) == len(dataset.treebank_ids) == 1
361
+ self.treebank_ranges.append((len(self), len(self) + len(dataset)))
362
+ self.treebank_ids.append(dataset.treebank_ids[0])
363
+ for s in range(len(dataset)):
364
+ for f in range(self.FACTORS):
365
+ factor = self.factors[f]
366
+ factor.strings.append(dataset.factors[f].strings[s])
367
+ factor.word_ids.append([])
368
+ for i, word in enumerate(dataset.factors[f].strings[s]):
369
+ if f == self.FORMS:
370
+ # We do not remap strings into IDs because the tokenizer will create the subwords IDs for us.
371
+ factor.word_ids[-1].append(0)
372
+ if f == self.HEAD:
373
+ factor.word_ids[-1].append(word)
374
+ elif f == self.LEMMAS:
375
+ factor.word_ids[-1].append(0)
376
+ lemma_transforms[(dataset.factors[self.FORMS].strings[s][i], word)] += 1
377
+ else:
378
+ if word not in factor.words_map:
379
+ factor.words_map[word] = len(factor.words)
380
+ factor.words.append(word)
381
+ factor.word_ids[-1].append(factor.words_map[word])
382
+ self.factors[f].word_ids[-1] = np.array(self.factors[f].word_ids[-1], np.int32)
383
+
384
+ # Construct lemma rules
385
+ self.finalize_lemma_rules(lemma_transforms, create_rules=True)
386
+
387
+ # Create an empty tokenize cache
388
+ self._tokenizer_cache = {}
389
+
390
+
391
+ class TorchUDDataset(torch.utils.data.Dataset):
392
+ def __init__(self, ud_dataset: UDDataset, tokenizers: list[transformers.PreTrainedTokenizer], args: argparse.Namespace, training: bool):
393
+ self.ud_dataset = ud_dataset
394
+ self.training = training
395
+ self._outputs_to_input = [args.tags.index(tag) for tag in args.embed_tags]
396
+
397
+ self._inputs = [ud_dataset.tokenize(tokenizer) for tokenizer in tokenizers]
398
+ self._outputs = [ud_dataset.factors[tag].word_ids for tag in args.tags]
399
+ if args.parse:
400
+ self._outputs.append(ud_dataset.factors[ud_dataset.HEAD].word_ids)
401
+ self._outputs.append(ud_dataset.factors[ud_dataset.DEPREL].word_ids)
402
+
403
+ # Trim the sentences if needed
404
+ if training and args.max_train_sentence_len:
405
+ trimmed_sentences = 0
406
+ for index in range(len(self)): # Over sentences
407
+ max_words, need_trimming = None, False
408
+ for tokens, word_indices in self._inputs: # Over transformers
409
+ if max_words is None:
410
+ max_words = len(word_indices[index])
411
+ while word_indices[index][max_words - 1, 1] >= args.max_train_sentence_len:
412
+ max_words -= 1
413
+ need_trimming = True
414
+ assert max_words >= 2, "Sentence too short after trimming"
415
+
416
+ if need_trimming:
417
+ for tokens, word_indices in self._inputs: # Over transformers
418
+ tokens[index] = tokens[index][:word_indices[index][max_words - 1, 1] + 1]
419
+ word_indices[index] = word_indices[index][:max_words]
420
+
421
+ for output in self._outputs:
422
+ output[index] = output[index][:max_words - 1] # No CLS tokens in outputs
423
+ if args.parse:
424
+ self._outputs[-2][index] = np.array([head if head < max_words else -1 for head in self._outputs[-2][index]], np.int32)
425
+
426
+ trimmed_sentences += 1
427
+ if trimmed_sentences:
428
+ print("Trimmed {} out of {} sentences".format(trimmed_sentences, len(self)))
429
+
430
+ def __len__(self):
431
+ return len(self.ud_dataset)
432
+
433
+ def __getitem__(self, index: int):
434
+ inputs = []
435
+ for tokens, word_indices in self._inputs:
436
+ inputs.append(torch.from_numpy(tokens[index]))
437
+ inputs.append(torch.from_numpy(word_indices[index]))
438
+ for i in self._outputs_to_input:
439
+ inputs.append(torch.from_numpy(self._outputs[i][index]))
440
+
441
+ outputs = []
442
+ for output in self._outputs:
443
+ outputs.append(torch.from_numpy(output[index]))
444
+
445
+ return inputs, outputs
446
+
447
+
448
+ class TorchUDDataLoader(torch.utils.data.DataLoader):
449
+ class MergedDatasetSampler(torch.utils.data.Sampler):
450
+ def __init__(self, ud_dataset: UDDataset, args: argparse.Namespace):
451
+ self._treebank_ranges = ud_dataset.treebank_ranges
452
+ self._sentences_per_epoch = args.steps_per_epoch * args.batch_size
453
+ self._generator = torch.Generator().manual_seed(args.seed)
454
+
455
+ treebank_weights = np.array([r[1] - r[0] for r in self._treebank_ranges], np.float32)
456
+ treebank_weights = treebank_weights ** args.train_sampling_exponent
457
+ treebank_weights /= np.sum(treebank_weights)
458
+ self._treebank_sizes = np.array(treebank_weights * self._sentences_per_epoch, np.int32)
459
+ self._treebank_sizes[:self._sentences_per_epoch - np.sum(self._treebank_sizes)] += 1
460
+ self._treebank_indices = [[] for _ in self._treebank_ranges]
461
+
462
+ def __len__(self):
463
+ return self._sentences_per_epoch
464
+
465
+ def __iter__(self):
466
+ indices = []
467
+ for i in range(len(self._treebank_ranges)):
468
+ required = self._treebank_sizes[i]
469
+ while required:
470
+ if not len(self._treebank_indices[i]):
471
+ self._treebank_indices[i] = self._treebank_ranges[i][0] + torch.randperm(
472
+ self._treebank_ranges[i][1] - self._treebank_ranges[i][0], generator=self._generator)
473
+ indices.append(self._treebank_indices[i][:required])
474
+ required -= min(len(self._treebank_indices[i]), required)
475
+ indices = torch.concatenate(indices, axis=0)
476
+ return iter(indices[torch.randperm(len(indices), generator=self._generator)])
477
+
478
+ def _collate_fn(self, batch):
479
+ inputs, outputs = zip(*batch)
480
+
481
+ batch_inputs = []
482
+ for sequences in zip(*inputs):
483
+ batch_inputs.append(torch.nn.utils.rnn.pad_sequence(sequences, batch_first=True, padding_value=-1))
484
+
485
+ batch_outputs = []
486
+ for output in zip(*outputs):
487
+ batch_outputs.append(torch.nn.utils.rnn.pad_sequence(output, batch_first=True, padding_value=-1))
488
+
489
+ batch_weights = [batch_output != -1 for batch_output in batch_outputs]
490
+
491
+ return tuple(batch_inputs), tuple(batch_outputs), tuple(batch_weights)
492
+
493
+ def __init__(self, dataset: TorchUDDataset, args: argparse.Namespace, **kwargs):
494
+ sampler = None
495
+ if dataset.training:
496
+ if len(dataset.ud_dataset.treebank_ranges) == 1:
497
+ sampler = torch.utils.data.RandomSampler(dataset, generator=torch.Generator().manual_seed(args.seed))
498
+ else:
499
+ assert args.steps_per_epoch is not None, "Steps per epoch must be specified when training on multiple treebanks"
500
+ sampler = self.MergedDatasetSampler(dataset.ud_dataset, args)
501
+ super().__init__(dataset, batch_size=args.batch_size, sampler=sampler, collate_fn=self._collate_fn, **kwargs)
502
+
503
+
504
+ class LatinPipeModel(keras.Model):
505
+ class HFTransformerLayer(keras.layers.Layer):
506
+ def __init__(self, transformer: transformers.PreTrainedModel, subword_combination: str, word_masking: float = None, mask_token_id: int = None, **kwargs):
507
+ super().__init__(**kwargs)
508
+ self._transformer = transformer
509
+ self._subword_combination = subword_combination
510
+ self._word_masking = word_masking
511
+ self._mask_token_id = mask_token_id
512
+
513
+ def call(self, inputs, word_indices, training=None):
514
+ if training and self._word_masking:
515
+ mask = keras.ops.cast(keras.random.uniform(keras.ops.shape(inputs), dtype="float32") < self._word_masking, inputs.dtype)
516
+ inputs = (1 - mask) * inputs + mask * self._mask_token_id
517
+ if (training or False) != self._transformer.training:
518
+ self._transformer.train(training or False)
519
+ if self._subword_combination != "last":
520
+ first_subwords = keras.ops.take_along_axis(
521
+ self._transformer(keras.ops.maximum(inputs, 0), attention_mask=inputs > -1).last_hidden_state,
522
+ keras.ops.expand_dims(keras.ops.maximum(word_indices[..., 0], 0), axis=-1),
523
+ axis=1,
524
+ )
525
+ if self._subword_combination != "first":
526
+ last_subwords = keras.ops.take_along_axis(
527
+ self._transformer(keras.ops.maximum(inputs, 0), attention_mask=inputs > -1).last_hidden_state,
528
+ keras.ops.expand_dims(keras.ops.maximum(word_indices[..., 1], 0), axis=-1),
529
+ axis=1,
530
+ )
531
+ if self._subword_combination == "first":
532
+ return first_subwords
533
+ elif self._subword_combination == "last":
534
+ return last_subwords
535
+ elif self._subword_combination == "sum":
536
+ return first_subwords + last_subwords
537
+ elif self._subword_combination == "concat":
538
+ return keras.ops.concatenate([first_subwords, last_subwords], axis=-1)
539
+ else:
540
+ raise ValueError("Unknown subword combination '{}'".format(self._subword_combination))
541
+
542
+ class LSTMTorch(keras.layers.Layer):
543
+ def __init__(self, units: int, **kwargs):
544
+ super().__init__(**kwargs)
545
+ self._units = units
546
+
547
+ def build(self, input_shape):
548
+ self._lstm = torch.nn.LSTM(input_shape[-1], self._units, batch_first=True, bidirectional=True)
549
+
550
+ def call(self, inputs, lengths):
551
+ packed_result, _ = self._lstm.module(torch.nn.utils.rnn.pack_padded_sequence(inputs, lengths.cpu(), batch_first=True, enforce_sorted=False))
552
+ unpacked_result = torch.nn.utils.rnn.unpack_sequence(packed_result)
553
+ return torch.nn.utils.rnn.pad_sequence(unpacked_result, batch_first=True, padding_value=0)
554
+
555
+ class GRUTorch(keras.layers.Layer):
556
+ def __init__(self, units: int, **kwargs):
557
+ super().__init__(**kwargs)
558
+ self._units = units
559
+
560
+ def build(self, input_shape):
561
+ self._gru = torch.nn.GRU(input_shape[-1], self._units, batch_first=True, bidirectional=True)
562
+
563
+ def call(self, inputs, lengths):
564
+ packed_result, _ = self._gru(torch.nn.utils.rnn.pack_padded_sequence(inputs, lengths.cpu(), batch_first=True, enforce_sorted=False))
565
+ unpacked_result = torch.nn.utils.rnn.unpack_sequence(packed_result)
566
+ return torch.nn.utils.rnn.pad_sequence(unpacked_result, batch_first=True, padding_value=0)
567
+
568
+ class ParsingHead(keras.layers.Layer):
569
+ def __init__(self, num_deprels: int, task_hidden_layer: int, parse_attention_dim: int, dropout: float, **kwargs):
570
+ super().__init__(**kwargs)
571
+ self._head_queries_hidden = keras.layers.Dense(task_hidden_layer, activation="relu")
572
+ self._head_queries_output = keras.layers.Dense(parse_attention_dim)
573
+ self._head_keys_hidden = keras.layers.Dense(task_hidden_layer, activation="relu")
574
+ self._head_keys_output = keras.layers.Dense(parse_attention_dim)
575
+ self._deprel_hidden = keras.layers.Dense(task_hidden_layer, activation="relu")
576
+ self._deprel_output = keras.layers.Dense(num_deprels)
577
+ self._dropout = keras.layers.Dropout(dropout)
578
+
579
+ def call(self, embeddings, embeddings_wo_root, embeddings_mask):
580
+ head_queries = self._head_queries_output(self._dropout(self._head_queries_hidden(embeddings_wo_root)))
581
+ head_keys = self._head_keys_output(self._dropout(self._head_keys_hidden(embeddings)))
582
+ head_scores = keras.ops.matmul(head_queries, keras.ops.transpose(head_keys, axes=[0, 2, 1])) / keras.ops.sqrt(head_queries.shape[-1])
583
+
584
+ head_scores_mask = keras.ops.cast(keras.ops.expand_dims(embeddings_mask, axis=1), head_scores.dtype)
585
+ head_scores = head_scores * head_scores_mask - 1e9 * (1 - head_scores_mask)
586
+
587
+ predicted_heads = keras.ops.argmax(head_scores, axis=-1)
588
+ predicted_head_embeddings = keras.ops.take_along_axis(embeddings, keras.ops.expand_dims(predicted_heads, axis=-1), axis=1)
589
+ deprel_hidden = keras.ops.concatenate([embeddings_wo_root, predicted_head_embeddings], axis=-1)
590
+ deprel_scores = self._deprel_output(self._dropout(self._deprel_hidden(deprel_hidden)))
591
+
592
+ return head_scores, deprel_scores
593
+
594
+ class SparseCategoricalCrossentropyWithLabelSmoothing(keras.losses.Loss):
595
+ def __init__(self, from_logits: bool, label_smoothing: float, **kwargs):
596
+ super().__init__(**kwargs)
597
+ self._from_logits = from_logits
598
+ self._label_smoothing = label_smoothing
599
+
600
+ def call(self, y_true, y_pred):
601
+ y_gold = keras.ops.one_hot(keras.ops.maximum(y_true, 0), y_pred.shape[-1])
602
+ if self._label_smoothing:
603
+ y_pred_mask = keras.ops.cast(y_pred > -1e9, y_pred.dtype)
604
+ y_gold = y_gold * (1 - self._label_smoothing) + y_pred_mask / keras.ops.sum(y_pred_mask, axis=-1, keepdims=True) * self._label_smoothing
605
+ return keras.losses.categorical_crossentropy(y_gold, y_pred, from_logits=self._from_logits)
606
+
607
+ def __init__(self, dataset: UDDataset, args: argparse.Namespace):
608
+ self._dataset = dataset
609
+ self._args = args
610
+
611
+ # Create the transformer models
612
+ self._tokenizers, self._transformers = [], []
613
+ for name in args.transformers:
614
+ self._tokenizers.append(transformers.AutoTokenizer.from_pretrained(name, add_prefix_space=True))
615
+
616
+ transformer, transformer_opts = transformers.AutoModel, {}
617
+ if "mt5" in name.lower():
618
+ transformer = transformers.MT5EncoderModel
619
+ if name.endswith(("LaTa", "PhilTa")):
620
+ transformer = transformers.T5EncoderModel
621
+ if name.endswith(("LaBerta", "PhilBerta")):
622
+ transformer_opts["add_pooling_layer"] = False
623
+
624
+ if args.load:
625
+ transformer = transformer.from_config(transformers.AutoConfig.from_pretrained(name), **transformer_opts)
626
+ else:
627
+ transformer = transformer.from_pretrained(name, **transformer_opts)
628
+
629
+ # Create additional tokens
630
+ additional_tokens = {}
631
+ if args.treebank_ids:
632
+ additional_tokens["additional_special_tokens"] = ["[TREEBANK_ID_{}]".format(i) for i in range(len(dataset.treebank_ids))]
633
+ if self._tokenizers[-1].cls_token_id is None: # Generate CLS token if not present (for representing sentence root in parsing).
634
+ additional_tokens["cls_token"] = "[CLS]"
635
+ if additional_tokens:
636
+ self._tokenizers[-1].add_special_tokens(additional_tokens)
637
+ transformer.resize_token_embeddings(len(self._tokenizers[-1]))
638
+ if args.treebank_ids:
639
+ assert len(self._tokenizers[-1].additional_special_tokens) == len(dataset.treebank_ids)
640
+
641
+ self._transformers.append(self.HFTransformerLayer(transformer, args.subword_combination, args.word_masking, self._tokenizers[-1].mask_token_id))
642
+
643
+ # Create the network
644
+ inputs = []
645
+ for _ in args.transformers:
646
+ inputs.extend([keras.layers.Input(shape=[None], dtype="int32"), keras.layers.Input(shape=[None, 2], dtype="int32")])
647
+ for _ in args.embed_tags:
648
+ inputs.append(keras.layers.Input(shape=[None], dtype="int32"))
649
+
650
+ # Run the transformer models
651
+ embeddings = []
652
+ for tokens, word_indices, transformer in zip(inputs[::2], inputs[1::2], self._transformers):
653
+ embeddings.append(transformer(tokens, word_indices))
654
+ embeddings = keras.layers.Concatenate(axis=-1)(embeddings)
655
+ embeddings = keras.layers.Dropout(args.dropout)(embeddings)
656
+
657
+ # Heads for the tagging tasks
658
+ outputs = []
659
+ for tag in args.tags:
660
+ hidden = keras.layers.Dense(args.task_hidden_layer, activation="relu")(embeddings[:, 1:])
661
+ hidden = keras.layers.Dropout(args.dropout)(hidden)
662
+ outputs.append(keras.layers.Dense(len(dataset.factors[tag].words))(hidden))
663
+
664
+ # Head for parsing
665
+ if args.parse:
666
+ if args.embed_tags:
667
+ all_embeddings = [embeddings]
668
+ for factor, input_tags in zip(args.embed_tags, inputs[-len(args.embed_tags):]):
669
+ embedding_layer = keras.layers.Embedding(len(dataset.factors[factor].words) + 1, 256)
670
+ all_embeddings.append(keras.layers.Dropout(args.dropout)(embedding_layer(keras.ops.pad(input_tags + 1, [(0, 0), (1, 0)]))))
671
+ embeddings = keras.ops.concatenate(all_embeddings, axis=-1)
672
+
673
+ for i in range(args.rnn_layers):
674
+ if args.rnn_type in ["LSTM", "GRU"]:
675
+ hidden = keras.layers.Bidirectional(getattr(keras.layers, args.rnn_type)(args.rnn_dim, return_sequences=True))(embeddings, mask=inputs[1][..., 0] > -1)
676
+ elif args.rnn_type in ["LSTMTorch", "GRUTorch"]:
677
+ hidden = getattr(self, args.rnn_type)(args.rnn_dim)(embeddings, keras.ops.sum(inputs[1][..., 0] > -1, axis=-1))
678
+ hidden = keras.layers.Dropout(args.dropout)(hidden)
679
+ embeddings = hidden + (embeddings if i else 0)
680
+
681
+ outputs.extend(self.ParsingHead(
682
+ len(dataset.factors[dataset.DEPREL].words), args.task_hidden_layer, args.parse_attention_dim, args.dropout,
683
+ )(embeddings, embeddings[:, 1:], inputs[1][..., 0] > -1))
684
+
685
+ super().__init__(inputs=inputs, outputs=outputs)
686
+ if args.load:
687
+ self.load_weights(args.load[0])
688
+
689
+ def compile(self, epoch_batches: int, frozen: bool):
690
+ args = self._args
691
+
692
+ for transformer in self._transformers:
693
+ transformer.trainable = not frozen
694
+
695
+ if frozen:
696
+ schedule = 1e-3
697
+ else:
698
+ schedule = keras.optimizers.schedules.CosineDecay(
699
+ 0. if args.learning_rate_warmup else args.learning_rate,
700
+ args.epochs * epoch_batches - args.learning_rate_warmup,
701
+ alpha=0.0 if args.learning_rate_decay != "none" else 1.0,
702
+ warmup_target=args.learning_rate if args.learning_rate_warmup else None,
703
+ warmup_steps=args.learning_rate_warmup,
704
+ )
705
+ if args.optimizer == "adam":
706
+ optimizer = keras.optimizers.Adam(schedule)
707
+ elif args.optimizer == "adafactor":
708
+ optimizer = keras.optimizers.Adafactor(schedule)
709
+ else:
710
+ raise ValueError("Unknown optimizer '{}'".format(args.optimizer))
711
+ super().compile(
712
+ optimizer=optimizer,
713
+ loss=self.SparseCategoricalCrossentropyWithLabelSmoothing(from_logits=True, label_smoothing=args.label_smoothing),
714
+ )
715
+
716
+ @property
717
+ def tokenizers(self) -> list[transformers.PreTrainedTokenizer]:
718
+ return self._tokenizers
719
+
720
+ def predict(self, dataloader: TorchUDDataLoader, save_as: str|None = None, args_override: argparse.Namespace|None = None) -> str:
721
+ ud_dataset = dataloader.dataset.ud_dataset
722
+ args = self._args if args_override is None else args_override
723
+ conllu, sentence = io.StringIO(), 0
724
+
725
+ for batch_inputs, _, _ in dataloader:
726
+ predictions = self.predict_on_batch(batch_inputs)
727
+ for b in range(len(batch_inputs[0])):
728
+ sentence_len = len(ud_dataset.factors[ud_dataset.FORMS].strings[sentence])
729
+ overrides = [None] * ud_dataset.FACTORS
730
+ for tag, prediction in zip(args.tags, predictions):
731
+ overrides[tag] = np.argmax(prediction[b, :sentence_len], axis=-1)
732
+ if args.parse:
733
+ heads, deprels = predictions[-2:]
734
+ padded_heads = np.zeros([sentence_len + 1, sentence_len + 1], dtype=np.float64)
735
+ padded_heads[1:] = heads[b, :sentence_len, :sentence_len + 1]
736
+ padded_heads[1:] -= np.max(padded_heads[1:], axis=-1, keepdims=True)
737
+ padded_heads[1:] -= np.log(np.sum(np.exp(padded_heads[1:]), axis=-1, keepdims=True))
738
+ if args.single_root:
739
+ selected_root = 1 + np.argmax(padded_heads[1:, 0])
740
+ padded_heads[:, 0] = np.nan
741
+ padded_heads[selected_root, 0] = 0
742
+ chosen_heads, _ = ufal.chu_liu_edmonds.chu_liu_edmonds(padded_heads)
743
+ overrides[ud_dataset.HEAD] = chosen_heads[1:]
744
+ overrides[ud_dataset.DEPREL] = np.argmax(deprels[b, :sentence_len], axis=-1)
745
+ ud_dataset.write_sentence(conllu, sentence, overrides)
746
+ sentence += 1
747
+
748
+ conllu = conllu.getvalue()
749
+ if save_as is not None:
750
+ os.makedirs(os.path.dirname(save_as), exist_ok=True)
751
+ with open(save_as, "w", encoding="utf-8") as conllu_file:
752
+ conllu_file.write(conllu)
753
+ return conllu
754
+
755
+ def evaluate(self, dataloader: TorchUDDataLoader, save_as: str|None = None, args_override: argparse.Namespace|None = None) -> tuple[str, dict[str, float]]:
756
+ conllu = self.predict(dataloader, save_as=save_as, args_override=args_override)
757
+ evaluation = latinpipe_evalatin24_eval.evaluate(dataloader.dataset.ud_dataset.conllu_for_eval, latinpipe_evalatin24_eval.load_conllu(io.StringIO(conllu)))
758
+ if save_as is not None:
759
+ os.makedirs(os.path.dirname(save_as), exist_ok=True)
760
+ with open(save_as + ".eval", "w", encoding="utf-8") as eval_file:
761
+ for metric, score in evaluation.items():
762
+ print("{}: {:.2f}%".format(metric, 100 * score.f1), file=eval_file)
763
+ return conllu, evaluation
764
+
765
+
766
+ class LatinPipeModelEnsemble:
767
+ def __init__(self, latinpipe_model: LatinPipeModel, args: argparse.Namespace):
768
+ self._latinpipe_model = latinpipe_model
769
+ self._args = args
770
+
771
+ def predict(self, dataloader: TorchUDDataLoader, save_as: str|None = None) -> str:
772
+ def log_softmax(logits):
773
+ logits -= np.max(logits, axis=-1, keepdims=True)
774
+ logits -= np.log(np.sum(np.exp(logits), axis=-1, keepdims=True))
775
+ return logits
776
+ ud_dataset = dataloader.dataset.ud_dataset
777
+
778
+ # First compute all predictions
779
+ overrides = [[0] * len(ud_dataset) if tag in self._args.tags + ([ud_dataset.HEAD, ud_dataset.DEPREL] if self._args.parse else []) else None
780
+ for tag in range(ud_dataset.FACTORS)]
781
+ for path in self._args.load:
782
+ self._latinpipe_model.load_weights(path)
783
+ sentence = 0
784
+ for batch_inputs, _, _ in dataloader:
785
+ predictions = self._latinpipe_model.predict_on_batch(batch_inputs)
786
+ for b in range(len(batch_inputs[0])):
787
+ sentence_len = len(ud_dataset.factors[ud_dataset.FORMS].strings[sentence])
788
+ for tag, prediction in zip(self._args.tags, predictions):
789
+ overrides[tag][sentence] += log_softmax(prediction[b, :sentence_len])
790
+ if self._args.parse:
791
+ overrides[ud_dataset.HEAD][sentence] += log_softmax(predictions[-2][b, :sentence_len, :sentence_len + 1])
792
+ overrides[ud_dataset.DEPREL][sentence] += log_softmax(predictions[-1][b, :sentence_len])
793
+ sentence += 1
794
+
795
+ # Predict the most likely class and generate CoNLL-U output
796
+ conllu = io.StringIO()
797
+ for sentence in range(len(ud_dataset)):
798
+ sentence_overrides = [None] * ud_dataset.FACTORS
799
+ for tag in self._args.tags:
800
+ sentence_overrides[tag] = np.argmax(overrides[tag][sentence], axis=-1)
801
+ if self._args.parse:
802
+ padded_heads = np.pad(overrides[ud_dataset.HEAD][sentence], [(1, 0), (0, 0)]).astype(np.float64)
803
+ if self._args.single_root:
804
+ selected_root = 1 + np.argmax(padded_heads[1:, 0])
805
+ padded_heads[:, 0] = np.nan
806
+ padded_heads[selected_root, 0] = 0
807
+ chosen_heads, _ = ufal.chu_liu_edmonds.chu_liu_edmonds(padded_heads)
808
+ sentence_overrides[ud_dataset.HEAD] = chosen_heads[1:]
809
+ sentence_overrides[ud_dataset.DEPREL] = np.argmax(overrides[ud_dataset.DEPREL][sentence], axis=-1)
810
+ ud_dataset.write_sentence(conllu, sentence, sentence_overrides)
811
+
812
+ conllu = conllu.getvalue()
813
+ if save_as is not None:
814
+ os.makedirs(os.path.dirname(save_as), exist_ok=True)
815
+ with open(save_as, "w", encoding="utf-8") as conllu_file:
816
+ conllu_file.write(conllu)
817
+ return conllu
818
+
819
+ def evaluate(self, dataloader: TorchUDDataLoader, save_as: str|None = None) -> tuple[str, dict[str, float]]:
820
+ return LatinPipeModel.evaluate(self, dataloader, save_as=save_as)
821
+
822
+
823
+ def main(params: list[str] | None = None) -> None:
824
+ args = parser.parse_args(params)
825
+
826
+ # If supplied, load configuration from a trained model
827
+ if args.load:
828
+ with open(os.path.join(os.path.dirname(args.load[0]), "options.json"), mode="r") as options_file:
829
+ args = argparse.Namespace(**{k: v for k, v in json.load(options_file).items() if k not in [
830
+ "dev", "exp", "load", "test", "threads", "verbose"]})
831
+ args = parser.parse_args(params, namespace=args)
832
+ else:
833
+ assert args.train, "Either --load or --train must be set."
834
+ assert args.transformers, "At least one transformer must be specified."
835
+
836
+ # Post-process arguments
837
+ args.embed_tags = [UDDataset.FACTORS_MAP[tag] for tag in args.embed_tags.split(",") if tag]
838
+ args.tags = [UDDataset.FACTORS_MAP[tag] for tag in args.tags.split(",") if tag]
839
+ args.script = os.path.basename(__file__)
840
+
841
+ # Create logdir
842
+ args.logdir = os.path.join("logs", "{}{}-{}-{}-s{}".format(
843
+ args.exp + "-" if args.exp else "",
844
+ os.path.splitext(os.path.basename(globals().get("__file__", "notebook")))[0],
845
+ os.environ.get("SLURM_JOB_ID", ""),
846
+ datetime.datetime.now().strftime("%y%m%d_%H%M%S"),
847
+ args.seed,
848
+ # ",".join(("{}={}".format(
849
+ # re.sub("(.)[^_]*_?", r"\1", k),
850
+ # ",".join(re.sub(r"^.*/", "", str(x)) for x in ((v if len(v) <= 1 else [v[0], "..."]) if isinstance(v, list) else [v])),
851
+ # ) for k, v in sorted(vars(args).items()) if k not in ["dev", "exp", "load", "test", "threads", "verbose"]))
852
+ ))
853
+ print(json.dumps(vars(args), sort_keys=True, ensure_ascii=False, indent=2))
854
+ os.makedirs(args.logdir, exist_ok=True)
855
+ with open(os.path.join(args.logdir, "options.json"), mode="w") as options_file:
856
+ json.dump(vars(args), options_file, sort_keys=True, ensure_ascii=False, indent=2)
857
+
858
+ # Set the random seed and the number of threads
859
+ keras.utils.set_random_seed(args.seed)
860
+ torch.set_num_threads(args.threads)
861
+ torch.set_num_interop_threads(args.threads)
862
+
863
+ # Load the data
864
+ if args.treebank_ids and max(len(args.train), len(args.dev), len(args.test)) > 1:
865
+ print("WARNING: With treebank_ids, treebanks must always be in the same position in the train/dev/test.")
866
+ if args.load:
867
+ train = UDDataset.from_mappings(os.path.join(os.path.dirname(args.load[0]), "mappings.pkl"))
868
+ else:
869
+ train = UDDatasetMerged([UDDataset(path, args, treebank_id=i if args.treebank_ids else None) for i, path in enumerate(args.train)])
870
+ train.save_mappings(os.path.join(args.logdir, "mappings.pkl"))
871
+ devs = [UDDataset(path, args, treebank_id=i if args.treebank_ids else None, train_dataset=train) for i, path in enumerate(args.dev)]
872
+ tests = [UDDataset(path, args, treebank_id=i if args.treebank_ids else None, train_dataset=train) for i, path in enumerate(args.test)]
873
+
874
+ # Create the model
875
+ model = LatinPipeModel(train, args)
876
+
877
+ # Create the dataloaders
878
+ if not args.load:
879
+ train_dataloader = TorchUDDataLoader(TorchUDDataset(train, model.tokenizers, args, training=True), args)
880
+ dev_dataloaders = [TorchUDDataLoader(TorchUDDataset(dataset, model.tokenizers, args, training=False), args) for dataset in devs]
881
+ test_dataloaders = [TorchUDDataLoader(TorchUDDataset(dataset, model.tokenizers, args, training=False), args) for dataset in tests]
882
+
883
+ # Perform prediction if requested
884
+ if args.load:
885
+ if len(args.load) > 1:
886
+ model = LatinPipeModelEnsemble(model, args)
887
+ for dataloader in dev_dataloaders:
888
+ model.evaluate(dataloader, save_as=os.path.splitext(
889
+ os.path.join(args.exp, os.path.basename(dataloader.dataset.ud_dataset.path)) if args.exp else dataloader.dataset.ud_dataset.path
890
+ )[0] + ".predicted.conllu")
891
+ for dataloader in test_dataloaders:
892
+ model.predict(dataloader, save_as=os.path.splitext(
893
+ os.path.join(args.exp, os.path.basename(dataloader.dataset.ud_dataset.path)) if args.exp else dataloader.dataset.ud_dataset.path
894
+ )[0] + ".predicted.conllu")
895
+ return
896
+
897
+ # Train the model
898
+ class Evaluator(keras.callbacks.Callback):
899
+ def __init__(self, wandb_log):
900
+ super().__init__()
901
+ self._wandb_log = wandb_log
902
+ self._metrics = [["", "Lemmas", "UPOS", "XPOS", "UFeats"][tag] for tag in args.tags] + (["UAS", "LAS"] if args.parse else [])
903
+
904
+ def on_epoch_end(self, epoch, logs=None):
905
+ logs["learning_rate"] = keras.ops.convert_to_numpy(model.optimizer.learning_rate)
906
+ for dataloader in dev_dataloaders + (test_dataloaders if epoch + 1 == args.epochs + args.epochs_frozen else []):
907
+ _, metrics = model.evaluate(dataloader, save_as=os.path.splitext(
908
+ os.path.join(args.logdir, os.path.basename(dataloader.dataset.ud_dataset.path))
909
+ )[0] + ".{:02d}.conllu".format(epoch + 1))
910
+ for metric, score in metrics.items():
911
+ if metric in self._metrics:
912
+ logs["{}_{}".format(os.path.splitext(os.path.basename(dataloader.dataset.ud_dataset.path))[0], metric)] = 100 * score.f1
913
+
914
+ aggregations = {"la_ud213": [("la_ittb-ud", 390_787), ("la_llct-ud", 194_143), ("la_proiel-ud", 177_558),
915
+ ("la_udante-ud", 30_450), ("la_perseus-ud", 16_486)]}
916
+ for split in ["dev", "test"]:
917
+ for metric in self._metrics:
918
+ for aggregation, parts in aggregations.items():
919
+ values = [logs.get("{}-{}_{}".format(part, split, metric), None) for part, _ in parts]
920
+ if all(value is not None for value in values):
921
+ logs["{}-{}_{}".format(aggregation, split, metric)] = np.mean(values)
922
+ logs["{}-sqrt-{}_{}".format(aggregation, split, metric)] = np.average(values, weights=[size**0.5 for _, size in parts])
923
+
924
+ if self._wandb_log:
925
+ self._wandb_log(logs, step=epoch + 1, commit=True)
926
+
927
+ wandb_log = None
928
+ if args.wandb:
929
+ import wandb
930
+ wandb.init(project="ufal-evalatin2024", name=args.exp, config=vars(args))
931
+ wandb_log = wandb.log
932
+ evaluator = Evaluator(wandb_log)
933
+ if args.epochs_frozen:
934
+ model.compile(len(train_dataloader), frozen=True)
935
+ model.fit(train_dataloader, epochs=args.epochs_frozen, verbose=args.verbose, callbacks=[evaluator])
936
+ if args.epochs:
937
+ model.compile(len(train_dataloader), frozen=False)
938
+ model.fit(train_dataloader, initial_epoch=args.epochs_frozen, epochs=args.epochs_frozen + args.epochs, verbose=args.verbose, callbacks=[evaluator])
939
+ if args.save_checkpoint:
940
+ model.save_weights(os.path.join(args.logdir, "model.weights.h5"))
941
+
942
+
943
+ if __name__ == "__main__":
944
+ main([] if "__file__" not in globals() else None)
src/evalatin2024-latinpipe/latinpipe_evalatin24_eval.py ADDED
@@ -0,0 +1,596 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+
3
+ # Compatible with Python 2.7 and 3.2+, can be used either as a module
4
+ # or a standalone executable.
5
+ #
6
+ # Copyright 2017, 2018 Institute of Formal and Applied Linguistics (UFAL),
7
+ # Faculty of Mathematics and Physics, Charles University, Czech Republic.
8
+ #
9
+ # This Source Code Form is subject to the terms of the Mozilla Public
10
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
11
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
+ #
13
+ # Authors: Milan Straka, Martin Popel <[email protected]>
14
+ #
15
+ # Changelog:
16
+ # - [12 Apr 2018] Version 0.9: Initial release.
17
+ # - [19 Apr 2018] Version 1.0: Fix bug in MLAS (duplicate entries in functional_children).
18
+ # Add --counts option.
19
+ # - [02 May 2018] Version 1.1: When removing spaces to match gold and system characters,
20
+ # consider all Unicode characters of category Zs instead of
21
+ # just ASCII space.
22
+ # - [12 Sep 2020] Version 1.2: Renamed to udpipe2_eval when releasing with UDPipe 2
23
+ # Allow evaluation with underscores in HEAD.
24
+ # - [26 Jul 2022] Version 1.3: Allow evaluation with multiple roots, if requested.
25
+ # - [13 Jan 2024] Version 1.4: Renamed to udpipe_evalatin24_eval when releasing with
26
+ # UDPipe EvaLatin 24.
27
+
28
+ # Command line usage
29
+ # ------------------
30
+ # udpipe_evalatin24_eval.py [-v] gold_conllu_file system_conllu_file
31
+ #
32
+ # - if no -v is given, only the official CoNLL18 UD Shared Task evaluation metrics
33
+ # are printed
34
+ # - if -v is given, more metrics are printed (as precision, recall, F1 score,
35
+ # and in case the metric is computed on aligned words also accuracy on these):
36
+ # - Tokens: how well do the gold tokens match system tokens
37
+ # - Sentences: how well do the gold sentences match system sentences
38
+ # - Words: how well can the gold words be aligned to system words
39
+ # - UPOS: using aligned words, how well does UPOS match
40
+ # - XPOS: using aligned words, how well does XPOS match
41
+ # - UFeats: using aligned words, how well does universal FEATS match
42
+ # - AllTags: using aligned words, how well does UPOS+XPOS+FEATS match
43
+ # - Lemmas: using aligned words, how well does LEMMA match
44
+ # - UAS: using aligned words, how well does HEAD match
45
+ # - LAS: using aligned words, how well does HEAD+DEPREL(ignoring subtypes) match
46
+ # - CLAS: using aligned words with content DEPREL, how well does
47
+ # HEAD+DEPREL(ignoring subtypes) match
48
+ # - MLAS: using aligned words with content DEPREL, how well does
49
+ # HEAD+DEPREL(ignoring subtypes)+UPOS+UFEATS+FunctionalChildren(DEPREL+UPOS+UFEATS) match
50
+ # - BLEX: using aligned words with content DEPREL, how well does
51
+ # HEAD+DEPREL(ignoring subtypes)+LEMMAS match
52
+ # - if -c is given, raw counts of correct/gold_total/system_total/aligned words are printed
53
+ # instead of precision/recall/F1/AlignedAccuracy for all metrics.
54
+
55
+ # API usage
56
+ # ---------
57
+ # - load_conllu(file)
58
+ # - loads CoNLL-U file from given file object to an internal representation
59
+ # - the file object should return str in both Python 2 and Python 3
60
+ # - raises UDError exception if the given file cannot be loaded
61
+ # - evaluate(gold_ud, system_ud)
62
+ # - evaluate the given gold and system CoNLL-U files (loaded with load_conllu)
63
+ # - raises UDError if the concatenated tokens of gold and system file do not match
64
+ # - returns a dictionary with the metrics described above, each metric having
65
+ # three fields: precision, recall and f1
66
+
67
+ # Description of token matching
68
+ # -----------------------------
69
+ # In order to match tokens of gold file and system file, we consider the text
70
+ # resulting from concatenation of gold tokens and text resulting from
71
+ # concatenation of system tokens. These texts should match -- if they do not,
72
+ # the evaluation fails.
73
+ #
74
+ # If the texts do match, every token is represented as a range in this original
75
+ # text, and tokens are equal only if their range is the same.
76
+
77
+ # Description of word matching
78
+ # ----------------------------
79
+ # When matching words of gold file and system file, we first match the tokens.
80
+ # The words which are also tokens are matched as tokens, but words in multi-word
81
+ # tokens have to be handled differently.
82
+ #
83
+ # To handle multi-word tokens, we start by finding "multi-word spans".
84
+ # Multi-word span is a span in the original text such that
85
+ # - it contains at least one multi-word token
86
+ # - all multi-word tokens in the span (considering both gold and system ones)
87
+ # are completely inside the span (i.e., they do not "stick out")
88
+ # - the multi-word span is as small as possible
89
+ #
90
+ # For every multi-word span, we align the gold and system words completely
91
+ # inside this span using LCS on their FORMs. The words not intersecting
92
+ # (even partially) any multi-word span are then aligned as tokens.
93
+
94
+
95
+ from __future__ import division
96
+ from __future__ import print_function
97
+
98
+ import argparse
99
+ import io
100
+ import sys
101
+ import unicodedata
102
+ import unittest
103
+
104
+ __version__ = "2.1.1-dev"
105
+
106
+
107
+ # CoNLL-U column names
108
+ ID, FORM, LEMMA, UPOS, XPOS, FEATS, HEAD, DEPREL, DEPS, MISC = range(10)
109
+
110
+ # Content and functional relations
111
+ CONTENT_DEPRELS = {
112
+ "nsubj", "obj", "iobj", "csubj", "ccomp", "xcomp", "obl", "vocative",
113
+ "expl", "dislocated", "advcl", "advmod", "discourse", "nmod", "appos",
114
+ "nummod", "acl", "amod", "conj", "fixed", "flat", "compound", "list",
115
+ "parataxis", "orphan", "goeswith", "reparandum", "root", "dep"
116
+ }
117
+
118
+ FUNCTIONAL_DEPRELS = {
119
+ "aux", "cop", "mark", "det", "clf", "case", "cc"
120
+ }
121
+
122
+ UNIVERSAL_FEATURES = {
123
+ "PronType", "NumType", "Poss", "Reflex", "Foreign", "Abbr", "Gender",
124
+ "Animacy", "Number", "Case", "Definite", "Degree", "VerbForm", "Mood",
125
+ "Tense", "Aspect", "Voice", "Evident", "Polarity", "Person", "Polite"
126
+ }
127
+
128
+ # UD Error is used when raising exceptions in this module
129
+ class UDError(Exception):
130
+ pass
131
+
132
+ # Load given CoNLL-U file into internal representation
133
+ def load_conllu(file, single_root=1):
134
+ # Internal representation classes
135
+ class UDRepresentation:
136
+ def __init__(self):
137
+ # Characters of all the tokens in the whole file.
138
+ # Whitespace between tokens is not included.
139
+ self.characters = []
140
+ # List of UDSpan instances with start&end indices into `characters`.
141
+ self.tokens = []
142
+ # List of UDWord instances.
143
+ self.words = []
144
+ # List of UDSpan instances with start&end indices into `characters`.
145
+ self.sentences = []
146
+ class UDSpan:
147
+ def __init__(self, start, end):
148
+ self.start = start
149
+ # Note that self.end marks the first position **after the end** of span,
150
+ # so we can use characters[start:end] or range(start, end).
151
+ self.end = end
152
+ class UDWord:
153
+ def __init__(self, span, columns, is_multiword):
154
+ # Span of this word (or MWT, see below) within ud_representation.characters.
155
+ self.span = span
156
+ # 10 columns of the CoNLL-U file: ID, FORM, LEMMA,...
157
+ self.columns = columns
158
+ # is_multiword==True means that this word is part of a multi-word token.
159
+ # In that case, self.span marks the span of the whole multi-word token.
160
+ self.is_multiword = is_multiword
161
+ # Reference to the UDWord instance representing the HEAD (or None if root).
162
+ self.parent = None
163
+ # List of references to UDWord instances representing functional-deprel children.
164
+ self.functional_children = []
165
+ # Only consider universal FEATS.
166
+ self.columns[FEATS] = "|".join(sorted(feat for feat in columns[FEATS].split("|")
167
+ if feat.split("=", 1)[0] in UNIVERSAL_FEATURES))
168
+ # Let's ignore language-specific deprel subtypes.
169
+ self.columns[DEPREL] = columns[DEPREL].split(":")[0]
170
+ # Precompute which deprels are CONTENT_DEPRELS and which FUNCTIONAL_DEPRELS
171
+ self.is_content_deprel = self.columns[DEPREL] in CONTENT_DEPRELS
172
+ self.is_functional_deprel = self.columns[DEPREL] in FUNCTIONAL_DEPRELS
173
+
174
+ ud = UDRepresentation()
175
+
176
+ # Load the CoNLL-U file
177
+ index, sentence_start = 0, None
178
+ while True:
179
+ line = file.readline()
180
+ if not line:
181
+ break
182
+ line = line.rstrip("\r\n")
183
+
184
+ # Handle sentence start boundaries
185
+ if sentence_start is None:
186
+ # Skip comments
187
+ if line.startswith("#"):
188
+ continue
189
+ # Start a new sentence
190
+ ud.sentences.append(UDSpan(index, 0))
191
+ sentence_start = len(ud.words)
192
+ if not line:
193
+ # Add parent and children UDWord links and check there are no cycles
194
+ def process_word(word):
195
+ if word.parent == "remapping":
196
+ raise UDError("There is a cycle in a sentence")
197
+ if word.parent is None:
198
+ if word.columns[HEAD] == "_":
199
+ word.parent = "missing"
200
+ else:
201
+ head = int(word.columns[HEAD])
202
+ if head < 0 or head > len(ud.words) - sentence_start:
203
+ raise UDError("HEAD '{}' points outside of the sentence".format(word.columns[HEAD]))
204
+ if head:
205
+ parent = ud.words[sentence_start + head - 1]
206
+ word.parent = "remapping"
207
+ process_word(parent)
208
+ word.parent = parent
209
+
210
+ for word in ud.words[sentence_start:]:
211
+ process_word(word)
212
+ # func_children cannot be assigned within process_word
213
+ # because it is called recursively and may result in adding one child twice.
214
+ for word in ud.words[sentence_start:]:
215
+ if word.parent and word.is_functional_deprel:
216
+ word.parent.functional_children.append(word)
217
+
218
+ # Check there is a single root node
219
+ if single_root:
220
+ if len([word for word in ud.words[sentence_start:] if word.parent is None]) > 1:
221
+ raise UDError("There are multiple roots in a sentence")
222
+
223
+ # End the sentence
224
+ ud.sentences[-1].end = index
225
+ sentence_start = None
226
+ continue
227
+
228
+ # Read next token/word
229
+ columns = line.split("\t")
230
+ if len(columns) != 10:
231
+ raise UDError("The CoNLL-U line does not contain 10 tab-separated columns: '{}'".format(line))
232
+
233
+ # Skip empty nodes
234
+ if "." in columns[ID]:
235
+ continue
236
+
237
+ # Delete spaces from FORM, so gold.characters == system.characters
238
+ # even if one of them tokenizes the space. Use any Unicode character
239
+ # with category Zs.
240
+ if sys.version_info < (3, 0) and isinstance(line, str):
241
+ columns[FORM] = columns[FORM].decode("utf-8")
242
+ columns[FORM] = "".join(filter(lambda c: unicodedata.category(c) != "Zs", columns[FORM]))
243
+ if sys.version_info < (3, 0) and isinstance(line, str):
244
+ columns[FORM] = columns[FORM].encode("utf-8")
245
+ if not columns[FORM]:
246
+ raise UDError("There is an empty FORM in the CoNLL-U file")
247
+
248
+ # Save token
249
+ ud.characters.extend(columns[FORM])
250
+ ud.tokens.append(UDSpan(index, index + len(columns[FORM])))
251
+ index += len(columns[FORM])
252
+
253
+ # Handle multi-word tokens to save word(s)
254
+ if "-" in columns[ID]:
255
+ try:
256
+ start, end = map(int, columns[ID].split("-"))
257
+ except:
258
+ raise UDError("Cannot parse multi-word token ID '{}'".format(columns[ID]))
259
+
260
+ for _ in range(start, end + 1):
261
+ word_line = file.readline().rstrip("\r\n")
262
+ word_columns = word_line.split("\t")
263
+ if len(word_columns) != 10:
264
+ raise UDError("The CoNLL-U line does not contain 10 tab-separated columns: '{}'".format(word_line))
265
+ ud.words.append(UDWord(ud.tokens[-1], word_columns, is_multiword=True))
266
+ # Basic tokens/words
267
+ else:
268
+ try:
269
+ word_id = int(columns[ID])
270
+ except:
271
+ raise UDError("Cannot parse word ID '{}'".format(columns[ID]))
272
+ if word_id != len(ud.words) - sentence_start + 1:
273
+ raise UDError("Incorrect word ID '{}' for word '{}', expected '{}'".format(columns[ID], columns[FORM], len(ud.words) - sentence_start + 1))
274
+
275
+ if columns[HEAD] != "_":
276
+ try:
277
+ head_id = int(columns[HEAD])
278
+ except:
279
+ raise UDError("Cannot parse HEAD '{}'".format(columns[HEAD]))
280
+ if head_id < 0:
281
+ raise UDError("HEAD cannot be negative")
282
+
283
+ ud.words.append(UDWord(ud.tokens[-1], columns, is_multiword=False))
284
+
285
+ if sentence_start is not None:
286
+ raise UDError("The CoNLL-U file does not end with empty line")
287
+
288
+ return ud
289
+
290
+ # Evaluate the gold and system treebanks (loaded using load_conllu).
291
+ def evaluate(gold_ud, system_ud):
292
+ class Score:
293
+ def __init__(self, gold_total, system_total, correct, aligned_total=None):
294
+ self.correct = correct
295
+ self.gold_total = gold_total
296
+ self.system_total = system_total
297
+ self.aligned_total = aligned_total
298
+ self.precision = correct / system_total if system_total else 0.0
299
+ self.recall = correct / gold_total if gold_total else 0.0
300
+ self.f1 = 2 * correct / (system_total + gold_total) if system_total + gold_total else 0.0
301
+ self.aligned_accuracy = correct / aligned_total if aligned_total else aligned_total
302
+ class AlignmentWord:
303
+ def __init__(self, gold_word, system_word):
304
+ self.gold_word = gold_word
305
+ self.system_word = system_word
306
+ class Alignment:
307
+ def __init__(self, gold_words, system_words):
308
+ self.gold_words = gold_words
309
+ self.system_words = system_words
310
+ self.matched_words = []
311
+ self.matched_words_map = {}
312
+ def append_aligned_words(self, gold_word, system_word):
313
+ self.matched_words.append(AlignmentWord(gold_word, system_word))
314
+ self.matched_words_map[system_word] = gold_word
315
+
316
+ def lower(text):
317
+ if sys.version_info < (3, 0) and isinstance(text, str):
318
+ return text.decode("utf-8").lower()
319
+ return text.lower()
320
+
321
+ def spans_score(gold_spans, system_spans):
322
+ correct, gi, si = 0, 0, 0
323
+ while gi < len(gold_spans) and si < len(system_spans):
324
+ if system_spans[si].start < gold_spans[gi].start:
325
+ si += 1
326
+ elif gold_spans[gi].start < system_spans[si].start:
327
+ gi += 1
328
+ else:
329
+ correct += gold_spans[gi].end == system_spans[si].end
330
+ si += 1
331
+ gi += 1
332
+
333
+ return Score(len(gold_spans), len(system_spans), correct)
334
+
335
+ def alignment_score(alignment, key_fn=None, filter_fn=None):
336
+ if filter_fn is not None:
337
+ gold = sum(1 for gold in alignment.gold_words if filter_fn(gold))
338
+ system = sum(1 for system in alignment.system_words if filter_fn(system))
339
+ aligned = sum(1 for word in alignment.matched_words if filter_fn(word.gold_word))
340
+ else:
341
+ gold = len(alignment.gold_words)
342
+ system = len(alignment.system_words)
343
+ aligned = len(alignment.matched_words)
344
+
345
+ if key_fn is None:
346
+ # Return score for whole aligned words
347
+ return Score(gold, system, aligned)
348
+
349
+ def gold_aligned_gold(word):
350
+ return word
351
+ def gold_aligned_system(word):
352
+ return alignment.matched_words_map.get(word, "NotAligned") if word is not None else None
353
+ correct = 0
354
+ for words in alignment.matched_words:
355
+ if filter_fn is None or filter_fn(words.gold_word):
356
+ if key_fn(words.gold_word, gold_aligned_gold) == key_fn(words.system_word, gold_aligned_system):
357
+ correct += 1
358
+
359
+ return Score(gold, system, correct, aligned)
360
+
361
+ def beyond_end(words, i, multiword_span_end):
362
+ if i >= len(words):
363
+ return True
364
+ if words[i].is_multiword:
365
+ return words[i].span.start >= multiword_span_end
366
+ return words[i].span.end > multiword_span_end
367
+
368
+ def extend_end(word, multiword_span_end):
369
+ if word.is_multiword and word.span.end > multiword_span_end:
370
+ return word.span.end
371
+ return multiword_span_end
372
+
373
+ def find_multiword_span(gold_words, system_words, gi, si):
374
+ # We know gold_words[gi].is_multiword or system_words[si].is_multiword.
375
+ # Find the start of the multiword span (gs, ss), so the multiword span is minimal.
376
+ # Initialize multiword_span_end characters index.
377
+ if gold_words[gi].is_multiword:
378
+ multiword_span_end = gold_words[gi].span.end
379
+ if not system_words[si].is_multiword and system_words[si].span.start < gold_words[gi].span.start:
380
+ si += 1
381
+ else: # if system_words[si].is_multiword
382
+ multiword_span_end = system_words[si].span.end
383
+ if not gold_words[gi].is_multiword and gold_words[gi].span.start < system_words[si].span.start:
384
+ gi += 1
385
+ gs, ss = gi, si
386
+
387
+ # Find the end of the multiword span
388
+ # (so both gi and si are pointing to the word following the multiword span end).
389
+ while not beyond_end(gold_words, gi, multiword_span_end) or \
390
+ not beyond_end(system_words, si, multiword_span_end):
391
+ if gi < len(gold_words) and (si >= len(system_words) or
392
+ gold_words[gi].span.start <= system_words[si].span.start):
393
+ multiword_span_end = extend_end(gold_words[gi], multiword_span_end)
394
+ gi += 1
395
+ else:
396
+ multiword_span_end = extend_end(system_words[si], multiword_span_end)
397
+ si += 1
398
+ return gs, ss, gi, si
399
+
400
+ def compute_lcs(gold_words, system_words, gi, si, gs, ss):
401
+ lcs = [[0] * (si - ss) for i in range(gi - gs)]
402
+ for g in reversed(range(gi - gs)):
403
+ for s in reversed(range(si - ss)):
404
+ if lower(gold_words[gs + g].columns[FORM]) == lower(system_words[ss + s].columns[FORM]):
405
+ lcs[g][s] = 1 + (lcs[g+1][s+1] if g+1 < gi-gs and s+1 < si-ss else 0)
406
+ lcs[g][s] = max(lcs[g][s], lcs[g+1][s] if g+1 < gi-gs else 0)
407
+ lcs[g][s] = max(lcs[g][s], lcs[g][s+1] if s+1 < si-ss else 0)
408
+ return lcs
409
+
410
+ def align_words(gold_words, system_words):
411
+ alignment = Alignment(gold_words, system_words)
412
+
413
+ gi, si = 0, 0
414
+ while gi < len(gold_words) and si < len(system_words):
415
+ if gold_words[gi].is_multiword or system_words[si].is_multiword:
416
+ # A: Multi-word tokens => align via LCS within the whole "multiword span".
417
+ gs, ss, gi, si = find_multiword_span(gold_words, system_words, gi, si)
418
+
419
+ if si > ss and gi > gs:
420
+ lcs = compute_lcs(gold_words, system_words, gi, si, gs, ss)
421
+
422
+ # Store aligned words
423
+ s, g = 0, 0
424
+ while g < gi - gs and s < si - ss:
425
+ if lower(gold_words[gs + g].columns[FORM]) == lower(system_words[ss + s].columns[FORM]):
426
+ alignment.append_aligned_words(gold_words[gs+g], system_words[ss+s])
427
+ g += 1
428
+ s += 1
429
+ elif lcs[g][s] == (lcs[g+1][s] if g+1 < gi-gs else 0):
430
+ g += 1
431
+ else:
432
+ s += 1
433
+ else:
434
+ # B: No multi-word token => align according to spans.
435
+ if (gold_words[gi].span.start, gold_words[gi].span.end) == (system_words[si].span.start, system_words[si].span.end):
436
+ alignment.append_aligned_words(gold_words[gi], system_words[si])
437
+ gi += 1
438
+ si += 1
439
+ elif gold_words[gi].span.start <= system_words[si].span.start:
440
+ gi += 1
441
+ else:
442
+ si += 1
443
+
444
+ return alignment
445
+
446
+ # Check that the underlying character sequences do match.
447
+ if gold_ud.characters != system_ud.characters:
448
+ index = 0
449
+ while index < len(gold_ud.characters) and index < len(system_ud.characters) and \
450
+ gold_ud.characters[index] == system_ud.characters[index]:
451
+ index += 1
452
+
453
+ raise UDError(
454
+ "The concatenation of tokens in gold file and in system file differ!\n" +
455
+ "First 20 differing characters in gold file: '{}' and system file: '{}'".format(
456
+ "".join(gold_ud.characters[index:index + 20]),
457
+ "".join(system_ud.characters[index:index + 20])
458
+ )
459
+ )
460
+
461
+ # Align words
462
+ alignment = align_words(gold_ud.words, system_ud.words)
463
+
464
+ # Compute the F1-scores
465
+ return {
466
+ "Tokens": spans_score(gold_ud.tokens, system_ud.tokens),
467
+ "Sentences": spans_score(gold_ud.sentences, system_ud.sentences),
468
+ "Words": alignment_score(alignment),
469
+ "UPOS": alignment_score(alignment, lambda w, _: w.columns[UPOS]),
470
+ "XPOS": alignment_score(alignment, lambda w, _: w.columns[XPOS]),
471
+ "UFeats": alignment_score(alignment, lambda w, _: w.columns[FEATS]),
472
+ "AllTags": alignment_score(alignment, lambda w, _: (w.columns[UPOS], w.columns[XPOS], w.columns[FEATS])),
473
+ "Lemmas": alignment_score(alignment, lambda w, ga: w.columns[LEMMA] if ga(w).columns[LEMMA] != "_" else "_"),
474
+ "UAS": alignment_score(alignment, lambda w, ga: ga(w.parent)),
475
+ "LAS": alignment_score(alignment, lambda w, ga: (ga(w.parent), w.columns[DEPREL])),
476
+ "CLAS": alignment_score(alignment, lambda w, ga: (ga(w.parent), w.columns[DEPREL]),
477
+ filter_fn=lambda w: w.is_content_deprel),
478
+ "MLAS": alignment_score(alignment, lambda w, ga: (ga(w.parent), w.columns[DEPREL], w.columns[UPOS], w.columns[FEATS],
479
+ [(ga(c), c.columns[DEPREL], c.columns[UPOS], c.columns[FEATS])
480
+ for c in w.functional_children]),
481
+ filter_fn=lambda w: w.is_content_deprel),
482
+ "BLEX": alignment_score(alignment, lambda w, ga: (ga(w.parent), w.columns[DEPREL],
483
+ w.columns[LEMMA] if ga(w).columns[LEMMA] != "_" else "_"),
484
+ filter_fn=lambda w: w.is_content_deprel),
485
+ }
486
+
487
+
488
+ def load_conllu_file(path, single_root=1):
489
+ _file = open(path, mode="r", **({"encoding": "utf-8"} if sys.version_info >= (3, 0) else {}))
490
+ return load_conllu(_file, single_root)
491
+
492
+ def evaluate_wrapper(args):
493
+ # Load CoNLL-U files
494
+ gold_ud = load_conllu_file(args.gold_file, args.single_root)
495
+ system_ud = load_conllu_file(args.system_file, args.single_root)
496
+ return evaluate(gold_ud, system_ud)
497
+
498
+ def main():
499
+ # Parse arguments
500
+ parser = argparse.ArgumentParser()
501
+ parser.add_argument("gold_file", type=str,
502
+ help="Name of the CoNLL-U file with the gold data.")
503
+ parser.add_argument("system_file", type=str,
504
+ help="Name of the CoNLL-U file with the predicted data.")
505
+ parser.add_argument("--verbose", "-v", default=False, action="store_true",
506
+ help="Print all metrics.")
507
+ parser.add_argument("--counts", "-c", default=False, action="store_true",
508
+ help="Print raw counts of correct/gold/system/aligned words instead of prec/rec/F1 for all metrics.")
509
+ parser.add_argument("--no_single_root", dest="single_root", default=True, action="store_false",
510
+ help="Allow multiple roots in a sentence.")
511
+ args = parser.parse_args()
512
+
513
+ # Evaluate
514
+ evaluation = evaluate_wrapper(args)
515
+
516
+ # Print the evaluation
517
+ if not args.verbose and not args.counts:
518
+ print("LAS F1 Score: {:.2f}".format(100 * evaluation["LAS"].f1))
519
+ print("MLAS Score: {:.2f}".format(100 * evaluation["MLAS"].f1))
520
+ print("BLEX Score: {:.2f}".format(100 * evaluation["BLEX"].f1))
521
+ else:
522
+ if args.counts:
523
+ print("Metric | Correct | Gold | Predicted | Aligned")
524
+ else:
525
+ print("Metric | Precision | Recall | F1 Score | AligndAcc")
526
+ print("-----------+-----------+-----------+-----------+-----------")
527
+ for metric in["Tokens", "Sentences", "Words", "UPOS", "XPOS", "UFeats", "AllTags", "Lemmas", "UAS", "LAS", "CLAS", "MLAS", "BLEX"]:
528
+ if args.counts:
529
+ print("{:11}|{:10} |{:10} |{:10} |{:10}".format(
530
+ metric,
531
+ evaluation[metric].correct,
532
+ evaluation[metric].gold_total,
533
+ evaluation[metric].system_total,
534
+ evaluation[metric].aligned_total or (evaluation[metric].correct if metric == "Words" else "")
535
+ ))
536
+ else:
537
+ print("{:11}|{:10.2f} |{:10.2f} |{:10.2f} |{}".format(
538
+ metric,
539
+ 100 * evaluation[metric].precision,
540
+ 100 * evaluation[metric].recall,
541
+ 100 * evaluation[metric].f1,
542
+ "{:10.2f}".format(100 * evaluation[metric].aligned_accuracy) if evaluation[metric].aligned_accuracy is not None else ""
543
+ ))
544
+
545
+ if __name__ == "__main__":
546
+ main()
547
+
548
+ # Tests, which can be executed with `python -m unittest udpipe_evalatin24_eval`.
549
+ class TestAlignment(unittest.TestCase):
550
+ @staticmethod
551
+ def _load_words(words):
552
+ """Prepare fake CoNLL-U files with fake HEAD to prevent multiple roots errors."""
553
+ lines, num_words = [], 0
554
+ for w in words:
555
+ parts = w.split(" ")
556
+ if len(parts) == 1:
557
+ num_words += 1
558
+ lines.append("{}\t{}\t_\t_\t_\t_\t{}\t_\t_\t_".format(num_words, parts[0], int(num_words>1)))
559
+ else:
560
+ lines.append("{}-{}\t{}\t_\t_\t_\t_\t_\t_\t_\t_".format(num_words + 1, num_words + len(parts) - 1, parts[0]))
561
+ for part in parts[1:]:
562
+ num_words += 1
563
+ lines.append("{}\t{}\t_\t_\t_\t_\t{}\t_\t_\t_".format(num_words, part, int(num_words>1)))
564
+ return load_conllu((io.StringIO if sys.version_info >= (3, 0) else io.BytesIO)("\n".join(lines+["\n"])))
565
+
566
+ def _test_exception(self, gold, system):
567
+ self.assertRaises(UDError, evaluate, self._load_words(gold), self._load_words(system))
568
+
569
+ def _test_ok(self, gold, system, correct):
570
+ metrics = evaluate(self._load_words(gold), self._load_words(system))
571
+ gold_words = sum((max(1, len(word.split(" ")) - 1) for word in gold))
572
+ system_words = sum((max(1, len(word.split(" ")) - 1) for word in system))
573
+ self.assertEqual((metrics["Words"].precision, metrics["Words"].recall, metrics["Words"].f1),
574
+ (correct / system_words, correct / gold_words, 2 * correct / (gold_words + system_words)))
575
+
576
+ def test_exception(self):
577
+ self._test_exception(["a"], ["b"])
578
+
579
+ def test_equal(self):
580
+ self._test_ok(["a"], ["a"], 1)
581
+ self._test_ok(["a", "b", "c"], ["a", "b", "c"], 3)
582
+
583
+ def test_equal_with_multiword(self):
584
+ self._test_ok(["abc a b c"], ["a", "b", "c"], 3)
585
+ self._test_ok(["a", "bc b c", "d"], ["a", "b", "c", "d"], 4)
586
+ self._test_ok(["abcd a b c d"], ["ab a b", "cd c d"], 4)
587
+ self._test_ok(["abc a b c", "de d e"], ["a", "bcd b c d", "e"], 5)
588
+
589
+ def test_alignment(self):
590
+ self._test_ok(["abcd"], ["a", "b", "c", "d"], 0)
591
+ self._test_ok(["abc", "d"], ["a", "b", "c", "d"], 1)
592
+ self._test_ok(["a", "bc", "d"], ["a", "b", "c", "d"], 2)
593
+ self._test_ok(["a", "bc b c", "d"], ["a", "b", "cd"], 2)
594
+ self._test_ok(["abc a BX c", "def d EX f"], ["ab a b", "cd c d", "ef e f"], 4)
595
+ self._test_ok(["ab a b", "cd bc d"], ["a", "bc", "d"], 2)
596
+ self._test_ok(["a", "bc b c", "d"], ["ab AX BX", "cd CX a"], 1)
src/evalatin2024-latinpipe/latinpipe_evalatin24_server.py ADDED
@@ -0,0 +1,433 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+
3
+ # This file is part of LatinPipe EvaLatin24
4
+ # <https://github.com/ufal/evalatin2024-latinpipe>.
5
+ #
6
+ # Copyright 2024 Institute of Formal and Applied Linguistics, Faculty of
7
+ # Mathematics and Physics, Charles University in Prague, Czech Republic.
8
+ #
9
+ # This Source Code Form is subject to the terms of the Mozilla Public
10
+ # License, v. 2.0. If a copy of the MPL was not distributed with this
11
+ # file, You can obtain one at http://mozilla.org/MPL/2.0/.
12
+
13
+ import argparse
14
+ import contextlib
15
+ import email.parser
16
+ import http.server
17
+ import itertools
18
+ import json
19
+ import os
20
+ import socketserver
21
+ import sys
22
+ import threading
23
+ import time
24
+ import unicodedata
25
+ import urllib.parse
26
+
27
+ import latinpipe_evalatin24
28
+ from latinpipe_evalatin24 import UDDataset # Make sure we can unpickle UDDataset mapping in this module.
29
+ import ufal.udpipe
30
+
31
+ __version__ = "1.0.0-dev"
32
+
33
+
34
+ class TooLongError(Exception):
35
+ pass
36
+
37
+ class Models:
38
+ class Model:
39
+ class Network:
40
+ _mutex = threading.Lock()
41
+
42
+ def __init__(self, path, server_args):
43
+ self._path = path
44
+ self._server_args = server_args
45
+ self.network, self.args, self.train = None, None, None
46
+
47
+ def load(self):
48
+ if self.network is not None:
49
+ return
50
+ with self._mutex:
51
+ if self.network is not None:
52
+ return
53
+
54
+ with open(os.path.join(self._path, "options.json"), mode="r") as options_file:
55
+ self.args = argparse.Namespace(**json.load(options_file))
56
+ self.args.batch_size = self._server_args.batch_size
57
+ self.args.load = [os.path.join(self._path, "model.weights.h5")]
58
+ self.train = latinpipe_evalatin24.UDDataset.from_mappings(os.path.join(self._path, "mappings.pkl"))
59
+ self.network = latinpipe_evalatin24.LatinPipeModel(self.train, self.args)
60
+
61
+ print("Loaded model {}".format(os.path.basename(self._path)), file=sys.stderr, flush=True)
62
+
63
+
64
+ def __init__(self, names, path, network, variant, acknowledgements, server_args):
65
+ self.names = names
66
+ self.acknowledgements = acknowledgements
67
+ self._network = network
68
+ self._variant = variant
69
+ self._server_args = server_args
70
+
71
+ # Load the tokenizer
72
+ tokenizer_path = os.path.join(path, "{}.tokenizer".format(variant))
73
+ self._tokenizer = ufal.udpipe.Model.load(tokenizer_path)
74
+ if self._tokenizer is None:
75
+ raise RuntimeError("Cannot load tokenizer from {}".format(tokenizer_path))
76
+
77
+ self._conllu_input = ufal.udpipe.InputFormat.newConlluInputFormat()
78
+ if self._conllu_input is None:
79
+ raise RuntimeError("Cannot create CoNLL-U input format")
80
+
81
+ self._conllu_output = ufal.udpipe.OutputFormat.newConlluOutputFormat()
82
+ if self._conllu_output is None:
83
+ raise RuntimeError("Cannot create CoNLL-U output format")
84
+
85
+ # Load the network if requested
86
+ if names[0] in server_args.preload_models or "all" in server_args.preload_models:
87
+ self._network.load()
88
+
89
+ def read(self, text, input_format):
90
+ reader = ufal.udpipe.InputFormat.newInputFormat(input_format)
91
+ if reader is None:
92
+ raise RuntimeError("Unknown input format '{}'".format(input_format))
93
+ # Do not return a generator, but a list to raise exceptions early
94
+ return list(self._read(text, reader))
95
+
96
+ def tokenize(self, text, tokenizer_options):
97
+ tokenizer = self._tokenizer.newTokenizer(tokenizer_options)
98
+ if tokenizer is None:
99
+ raise RuntimeError("Cannot create tokenizer.")
100
+ # Do not return a generator, but a list to raise exceptions early
101
+ return list(self._read(text, tokenizer))
102
+
103
+ def _read(self, text, reader):
104
+ sentence = ufal.udpipe.Sentence()
105
+ processing_error = ufal.udpipe.ProcessingError()
106
+ reader.setText(text)
107
+ while reader.nextSentence(sentence, processing_error):
108
+ if len(sentence.words) > 1001:
109
+ raise TooLongError()
110
+ yield sentence
111
+ sentence = ufal.udpipe.Sentence()
112
+ if processing_error.occurred():
113
+ raise RuntimeError("Cannot read input data: '{}'".format(processing_error.message))
114
+
115
+ def create_writer(self, output_format):
116
+ writer = ufal.udpipe.OutputFormat.newOutputFormat(output_format)
117
+ if writer is None:
118
+ raise RuntimeError("Unknown output format '{}'".format(output_format))
119
+ return writer
120
+
121
+ def predict(self, sentences, tag, parse, writer):
122
+ # Run the model
123
+ if tag or parse:
124
+ # Load the network if it has not been loaded already
125
+ self._network.load()
126
+
127
+ conllu_input = []
128
+ for sentence in sentences:
129
+ conllu_input.append(self._conllu_output.writeSentence(sentence))
130
+
131
+ time_ds = time.time()
132
+ # Create LatinPipe2Dataset
133
+ dataset = latinpipe_evalatin24.UDDataset(
134
+ "<web_input>", self._network.args, text="".join(conllu_input), train_dataset=self._network.train)
135
+ dataloader = latinpipe_evalatin24.TorchUDDataLoader(latinpipe_evalatin24.TorchUDDataset(
136
+ dataset, self._network.network.tokenizers, self._network.args, training=False), self._network.args)
137
+
138
+ # Prepare network arguments
139
+ current_args = argparse.Namespace(**vars(self._network.args))
140
+ if not tag: current_args.tags = []
141
+ if not parse: current_args.parse = 0
142
+
143
+ # Perform the prediction
144
+ time_nws = time.time()
145
+ with self._server_args.optional_semaphore:
146
+ time_nw = time.time()
147
+ predicted = self._network.network.predict(dataloader, args_override=current_args)
148
+ time_rd = time.time()
149
+
150
+ # Load the predicted CoNLL-U to ufal.udpipe sentences
151
+ sentences = self._read(predicted, self._conllu_input)
152
+
153
+ print("Request, DS {:.2f}ms,".format(1000 * (time_nws - time_ds)),
154
+ "NW {:.2f}+{:.2f}ms,".format(1000 * (time_rd - time_nw), 1000 * (time_nw - time_nws)),
155
+ "RD {:.2f}ms.".format(1000 * (time.time() - time_rd)),
156
+ file=sys.stderr, flush=True)
157
+
158
+ # Generate output
159
+ output = []
160
+ for sentence in sentences:
161
+ output.append(writer.writeSentence(sentence))
162
+ output.append(writer.finishDocument())
163
+ return "".join(output)
164
+
165
+ def __init__(self, server_args):
166
+ self.default_model = server_args.default_model
167
+ self.models_list = []
168
+ self.models_by_names = {}
169
+ networks_by_path = {}
170
+
171
+ for i in range(0, len(server_args.models), 4):
172
+ names, path, variant, acknowledgements = server_args.models[i:i+4]
173
+ names = names.split(":")
174
+ names = [name.split("-") for name in names]
175
+ names = ["-".join(parts[:None if not i else -i]) for parts in names for i in range(len(parts))]
176
+
177
+ if not path in networks_by_path:
178
+ networks_by_path[path] = self.Model.Network(path, server_args)
179
+ self.models_list.append(self.Model(names, path, networks_by_path[path], variant, acknowledgements, server_args))
180
+ for name in names:
181
+ self.models_by_names.setdefault(name, self.models_list[-1])
182
+
183
+ # Check the default model exists
184
+ assert self.default_model in self.models_by_names
185
+
186
+
187
+ class LatinPipeServer(socketserver.ThreadingTCPServer):
188
+ class LatinPipeServerRequestHandler(http.server.BaseHTTPRequestHandler):
189
+ protocol_version = "HTTP/1.1"
190
+
191
+ def respond(request, content_type, code=200, additional_headers={}):
192
+ request.close_connection = True
193
+ request.send_response(code)
194
+ request.send_header("Connection", "close")
195
+ request.send_header("Content-Type", content_type)
196
+ request.send_header("Access-Control-Allow-Origin", "*")
197
+ for key, value in additional_headers.items():
198
+ request.send_header(key, value)
199
+ request.end_headers()
200
+
201
+ def respond_error(request, message, code=400):
202
+ request.respond("text/plain", code)
203
+ request.wfile.write(message.encode("utf-8"))
204
+
205
+ def do_GET(request):
206
+ # Parse the URL
207
+ params = {}
208
+ try:
209
+ request.path = request.path.encode("iso-8859-1").decode("utf-8")
210
+ url = urllib.parse.urlparse(request.path)
211
+ for name, value in urllib.parse.parse_qsl(url.query, encoding="utf-8", keep_blank_values=True, errors="strict"):
212
+ params[name] = value
213
+ except:
214
+ return request.respond_error("Cannot parse request URL.")
215
+
216
+ # Parse the body of a POST request
217
+ if request.command == "POST":
218
+ if request.headers.get("Transfer-Encoding", "identity").lower() != "identity":
219
+ return request.respond_error("Only 'identity' Transfer-Encoding of payload is supported for now.")
220
+
221
+ try:
222
+ content_length = int(request.headers["Content-Length"])
223
+ except:
224
+ return request.respond_error("The Content-Length of payload is required.")
225
+
226
+ if content_length > request.server._server_args.max_request_size:
227
+ return request.respond_error("The payload size is too large.")
228
+
229
+ # Raw text on input for weblicht
230
+ if url.path.startswith("/weblicht/"):
231
+ # Ignore all but `model` GET param
232
+ params = {"model": params["model"]} if "model" in params else {}
233
+
234
+ try:
235
+ params["data"] = request.rfile.read(content_length).decode("utf-8")
236
+ except:
237
+ return request.respond_error("The payload is not in UTF-8 encoding.")
238
+
239
+ if url.path == "/weblicht/tokenize": params["tokenizer"] = ""
240
+ else: params["input"] = "conllu"
241
+ params["output"] = "conllu"
242
+ if url.path == "/weblicht/tag": params["tagger"] = ""
243
+ if url.path == "/weblicht/parse": params["parser"] = ""
244
+ # multipart/form-data
245
+ elif request.headers.get("Content-Type", "").startswith("multipart/form-data"):
246
+ try:
247
+ parser = email.parser.BytesFeedParser()
248
+ parser.feed(b"Content-Type: " + request.headers["Content-Type"].encode("ascii") + b"\r\n\r\n")
249
+ while content_length:
250
+ parser.feed(request.rfile.read(min(content_length, 4096)))
251
+ content_length -= min(content_length, 4096)
252
+ for part in parser.close().get_payload():
253
+ name = part.get_param("name", header="Content-Disposition")
254
+ if name:
255
+ params[name] = part.get_payload(decode=True).decode("utf-8")
256
+ except:
257
+ return request.respond_error("Cannot parse the multipart/form-data payload.")
258
+ # application/x-www-form-urlencoded
259
+ elif request.headers.get("Content-Type", "").startswith("application/x-www-form-urlencoded"):
260
+ try:
261
+ for name, value in urllib.parse.parse_qsl(
262
+ request.rfile.read(content_length).decode("utf-8"), encoding="utf-8", keep_blank_values=True, errors="strict"):
263
+ params[name] = value
264
+ except:
265
+ return request.respond_error("Cannot parse the application/x-www-form-urlencoded payload.")
266
+ else:
267
+ return request.respond_error("Unsupported payload Content-Type '{}'.".format(request.headers.get("Content-Type", "<none>")))
268
+
269
+ # Handle /models
270
+ if url.path == "/models":
271
+ response = {
272
+ "models": {model.names[0]: ["tokenizer", "tagger", "parser"] for model in request.server._models.models_list},
273
+ "default_model": request.server._models.default_model,
274
+ }
275
+ request.respond("application/json")
276
+ request.wfile.write(json.dumps(response, indent=1).encode("utf-8"))
277
+ # Handle /process
278
+ elif url.path in ["/process", "/weblicht/tokenize", "/weblicht/tag", "/weblicht/parse"]:
279
+ weblicht = url.path.startswith("/weblicht")
280
+
281
+ if "data" not in params:
282
+ return request.respond_error("The parameter 'data' is required.")
283
+ params["data"] = unicodedata.normalize("NFC", params["data"])
284
+
285
+ model = params.get("model", request.server._models.default_model)
286
+ if model not in request.server._models.models_by_names:
287
+ return request.respond_error("The requested model '{}' does not exist.".format(model))
288
+ model = request.server._models.models_by_names[model]
289
+
290
+ # Start by reading and optionally tokenizing the input data.
291
+ if "tokenizer" in params:
292
+ try:
293
+ sentences = model.tokenize(params["data"], params["tokenizer"])
294
+ except TooLongError:
295
+ return request.respond_error("During tokenization, sentence longer than 1000 words was found, aborting.\nThat should only happen with presegmented input.\nPlease make sure you do not generate such long sentences.\n")
296
+ except:
297
+ return request.respond_error("An error occured during tokenization of the input.")
298
+ else:
299
+ try:
300
+ sentences = model.read(params["data"], params.get("input", "conllu"))
301
+ except TooLongError:
302
+ return request.respond_error("Sentence longer than 1000 words was found on input, aborting.\nPlease make sure the input sentences have at most 1000 words.\n")
303
+ except:
304
+ return request.respond_error("Cannot parse the input in '{}' format.".format(params.get("input", "conllu")))
305
+ infclen = sum(sum(len(word.form) for word in sentence.words[1:]) for sentence in sentences)
306
+
307
+ # Create the writer
308
+ output_format = params.get("output", "conllu")
309
+ try:
310
+ writer = model.create_writer(output_format)
311
+ except:
312
+ return request.respond_error("Unknown output format '{}'.".format(output_format))
313
+
314
+ # Process the data
315
+ tag, parse, output_format = "tagger" in params, "parser" in params, params.get("output", "conllu")
316
+ batch, started_responding = [], False
317
+ try:
318
+ for sentence in itertools.chain(sentences, ["EOF"]):
319
+ if sentence == "EOF" or len(batch) == request.server._server_args.batch_size:
320
+ output = model.predict(batch, tag, parse, writer)
321
+ if not started_responding:
322
+ # The first batch is ready, we commit to generate output.
323
+ started_responding=True
324
+ if weblicht:
325
+ request.respond("application/conllu")
326
+ else:
327
+ request.respond("application/json", additional_headers={"X-Billing-Input-NFC-Len": str(infclen)})
328
+ request.wfile.write(json.dumps({
329
+ "model": model.names[0],
330
+ "acknowledgements": ["https://github.com/ufal/evalatin2024-latinpipe", model.acknowledgements],
331
+ "result": "",
332
+ }, indent=1)[:-3].encode("utf-8"))
333
+ if output_format == "conllu":
334
+ request.wfile.write(json.dumps(
335
+ "# generator = LatinPipe EvaLatin24, https://lindat.mff.cuni.cz/services/udpipe\n"
336
+ "# latinpipe_model = {}\n"
337
+ "# latinpipe_model_licence = CC BY-NC-SA\n".format(model.names[0]))[1:-1].encode("utf-8"))
338
+ if weblicht:
339
+ request.wfile.write(output.encode("utf-8"))
340
+ else:
341
+ request.wfile.write(json.dumps(output, ensure_ascii=False)[1:-1].encode("utf-8"))
342
+ batch = []
343
+ batch.append(sentence)
344
+ if not weblicht:
345
+ request.wfile.write(b'"\n}\n')
346
+ except:
347
+ import traceback
348
+ traceback.print_exc(file=sys.stderr)
349
+ sys.stderr.flush()
350
+
351
+ if not started_responding:
352
+ request.respond_error("An internal error occurred during processing.")
353
+ else:
354
+ if weblicht:
355
+ request.wfile.write(b'\n\nAn internal error occurred during processing, producing incorrect CoNLL-U!')
356
+ else:
357
+ request.wfile.write(b'",\n"An internal error occurred during processing, producing incorrect JSON!"')
358
+ # Unknown URL
359
+ else:
360
+ request.respond_error("No handler for the given URL '{}'".format(url.path), code=404)
361
+
362
+ def do_POST(request):
363
+ return request.do_GET()
364
+
365
+ daemon_threads = False
366
+
367
+ def __init__(self, server_args, models):
368
+ super().__init__(("", server_args.port), self.LatinPipeServerRequestHandler)
369
+
370
+ self._server_args = server_args
371
+ self._models = models
372
+
373
+ def server_bind(self):
374
+ import socket
375
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
376
+ self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEPORT, 1)
377
+ super().server_bind()
378
+
379
+ def service_actions(self):
380
+ if isinstance(getattr(self, "_threads", None), list):
381
+ if len(self._threads) >= 1024:
382
+ self._threads = [thread for thread in self._threads if thread.is_alive()]
383
+
384
+
385
+ if __name__ == "__main__":
386
+ import signal
387
+ import threading
388
+
389
+ # Parse server arguments
390
+ parser = argparse.ArgumentParser()
391
+ parser.add_argument("port", type=int, help="Port to use")
392
+ parser.add_argument("default_model", type=str, help="Default model")
393
+ parser.add_argument("models", type=str, nargs="+", help="Models to serve")
394
+ parser.add_argument("--batch_size", default=32, type=int, help="Batch size")
395
+ parser.add_argument("--concurrent", default=None, type=int, help="Concurrent computations of NN")
396
+ parser.add_argument("--logfile", default=None, type=str, help="Log path")
397
+ parser.add_argument("--max_request_size", default=4096*1024, type=int, help="Maximum request size")
398
+ parser.add_argument("--preload_models", default=[], nargs="*", type=str, help="Models to preload, or `all`")
399
+ parser.add_argument("--threads", default=0, type=int, help="Threads to use")
400
+ args = parser.parse_args()
401
+
402
+ # Log stderr to logfile if given
403
+ if args.logfile is not None:
404
+ sys.stderr = open(args.logfile, "a", encoding="utf-8")
405
+
406
+ if args.threads:
407
+ # Limit the number of threads if requested
408
+ import torch
409
+ torch.set_num_threads(args.threads)
410
+ torch.set_num_interop_threads(args.threads)
411
+
412
+ # Load the models
413
+ models = Models(args)
414
+
415
+ # Create a semaphore if needed
416
+ args.optional_semaphore = threading.Semaphore(args.concurrent) if args.concurrent is not None else contextlib.nullcontext()
417
+
418
+ # Create the server
419
+ server = LatinPipeServer(args, models)
420
+ server_thread = threading.Thread(target=server.serve_forever, daemon=True)
421
+ server_thread.start()
422
+
423
+ print("Started LatinPipe server on port {}.".format(args.port), file=sys.stderr)
424
+ print("To stop it gracefully, either send SIGINT (Ctrl+C) or SIGUSR1.", file=sys.stderr, flush=True)
425
+
426
+ # Wait until the server should be closed
427
+ signal.pthread_sigmask(signal.SIG_BLOCK, [signal.SIGINT, signal.SIGUSR1])
428
+ signal.sigwait([signal.SIGINT, signal.SIGUSR1])
429
+ print("Initiating shutdown of the LatinPipe EvaLatin24 server.", file=sys.stderr, flush=True)
430
+ server.shutdown()
431
+ print("Stopped handling new requests, processing all current ones.", file=sys.stderr, flush=True)
432
+ server.server_close()
433
+ print("Finished shutdown of the LatinPipe EvaLatin24 server.", file=sys.stderr, flush=True)
src/evalatin2024-latinpipe/parsed.conllu ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # sent_id = S0001
2
+ # text = Uma frase como exemplo.
3
+ 1 Uma um DET _ Definite=Ind|Gender=Fem|Number=Sing|PronType=Art 2 det _ _
4
+ 2 frase frase NOUN _ Gender=Fem|Number=Sing 0 root _ _
5
+ 3 como como ADP _ _ 4 case _ _
6
+ 4 exemplo exemplo NOUN _ Gender=Masc|Number=Sing 2 nmod _ SpaceAfter=No
7
+ 5 . . PUNCT _ _ 2 punct _ _
8
+
9
+ # sent_id = S0001
10
+ # text = O menino viu a menina com o telescópio.
11
+ 1 O _ _ _ _ _ _ _ _
12
+ 2 menino _ _ _ _ _ _ _ _
13
+ 3 viu _ _ _ _ _ _ _ _
14
+ 4 a _ _ _ _ _ _ _ _
15
+ 5 menina _ _ _ _ _ _ _ _
16
+ 6 com _ _ _ _ _ _ _ _
17
+ 7 o _ _ _ _ _ _ _ _
18
+ 8 telescópio _ _ _ _ _ _ _ SpaceAfter=No
19
+ 9 . _ _ _ _ _ _ _ _
20
+
src/evalatin2024-latinpipe/requirements.txt ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
 
1
+ keras
2
+ torch
3
+ --extra-index-url=https://download.pytorch.org/whl/cu118
4
+ transformers
5
+ ufal.chu-liu-edmonds
6
+
7
+ # For latinpipe_evalatin24_server, you also need
8
+ # ufal.udpipe
src/img/c4ia.png ADDED
src/img/icmc.png ADDED

Git LFS Details

  • SHA256: b7932ec657766c81627a54ce020234ffc3ac3439e196bec13fee0b2e3bfce08f
  • Pointer size: 131 Bytes
  • Size of remote file: 131 kB
src/img/inova_nobackground.png ADDED
src/img/mcti_nobackground.png ADDED
src/img/motorola_nobackground.png ADDED
src/img/nilc-removebg.png ADDED
src/img/softex_nobackground.png ADDED
src/img/wordcloud_brasil5.png ADDED

Git LFS Details

  • SHA256: d8a319d54d21a54d53b406280df117b14dbb436a0d6fccdf1a5dc82fa2950624
  • Pointer size: 131 Bytes
  • Size of remote file: 268 kB
src/portSentencer/abbrev.txt ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ dr.
2
+ dra.
3
+ sr.
4
+ sra.
5
+ prof.
6
+ profa.
7
+ Dr.
8
+ Dra.
9
+ Sr.
10
+ Sra.
11
+ Prof.
12
+ Profa.
13
+ DR.
14
+ DRA.
15
+ SR.
16
+ SRA.
17
+ PROF.
18
+ PROFA.
19
+ ilmo.
20
+ Ilmo.
21
+ ILMO.
22
+ bel.
23
+ Bel.
24
+ BEL.
25
+ eng.
26
+ Eng.
27
+ ENG.
28
+ reg.
29
+ Reg.
30
+ REG.
31
+ visc.
32
+ Visc.
33
+ VISC.
34
+ bar.
35
+ Bar.
36
+ BAR.
37
+ cond.
38
+ Cond.
39
+ COND.
40
+ séc.
41
+ Séc.
42
+ SÉC.
43
+ jr.
44
+ Jr.
45
+ JR.
46
+ ir.
47
+ Ir.
48
+ IR.
49
+ st.
50
+ St.
51
+ ST.
52
+ app.
53
+ App.
54
+ APP.
55
+ gov.
56
+ Gov.
57
+ GOV.
58
+ des.
59
+ Des.
60
+ DES.
61
+ gen.
62
+ Gen.
63
+ GEN.
64
+ gal.
65
+ Gal.
66
+ GAL.
67
+ cel.
68
+ Cel.
69
+ CEL.
70
+ col.
71
+ Col.
72
+ COL.
73
+ maj.
74
+ Maj.
75
+ MAJ.
76
+ ten.
77
+ Ten.
78
+ TEN.
79
+ cap.
80
+ Cap.
81
+ CAP.
82
+ capt.
83
+ Capt.
84
+ CAPT.
85
+ com.
86
+ Com.
87
+ COM.
88
+ brig.
89
+ Brig.
90
+ BRIG.
91
+ estac.
92
+ Estac.
93
+ ESTAC.
94
+ tel.
95
+ Tel.
96
+ TEL.
97
+ ave.
98
+ Ave.
99
+ AVE.
100
+ av.
101
+ Av.
102
+ AV.
103
+ trav.
104
+ Trav.
105
+ TRAV.
106
+ con.
107
+ Con.
108
+ CON.
109
+ jd.
110
+ Jd.
111
+ JD.
112
+ ed.
113
+ Ed.
114
+ ED.
115
+ lj.
116
+ Lj.
117
+ LJ.
118
+ cj.
119
+ Cj.
120
+ CJ.
121
+ apto.
122
+ Apto.
123
+ APTO.
124
+ apt.
125
+ Apt.
126
+ APT.
127
+ ingr.
128
+ Ingr.
129
+ INGR.
130
+ ap.
131
+ Ap.
132
+ AP.
133
+ dir.
134
+ Dir.
135
+ DIR.
136
+ min.
137
+ Min.
138
+ MIN.
139
+ sec.
140
+ Sec.
141
+ SEC.
142
+ kg.
143
+ Kg.
144
+ KG.
145
+ ml.
146
+ Ml.
147
+ ML.
148
+ km.
149
+ Km.
150
+ KM.
151
+ cm.
152
+ Cm.
153
+ CM.
154
+ vol.
155
+ Vol.
156
+ VOL.
157
+ PP.
158
+ pp.
159
+ Pp
160
+ pag.
161
+ Pag
162
+ PAG.
163
+ pág.
164
+ Pág
165
+ PÁG.
166
+ al.
167
+ Al.
168
+ AL.
169
+ etc.
170
+ i.e.
171
+ e.g.
172
+ cia.
173
+ Cia.
174
+ CIA.
175
+ co.
176
+ Co.
177
+ CO.
178
+ ltda.
179
+ Ltda.
180
+ LTDA.
181
+ ex.
182
+ Ex.
183
+ EX.
184
+ ac.
185
+ Ac.
186
+ AC.
187
+ dc.
188
+ Dc.
189
+ DC.
190
+ bros.
191
+ Bros.
192
+ BROS.
193
+ pq.
194
+ Pq.
195
+ PQ.
196
+ br.
197
+ Br.
198
+ BR.
199
+ cent.
200
+ Cent.
201
+ CENT.
202
+ ft.
203
+ Ft.
204
+ FT.
205
+ net.
206
+ Net.
207
+ NET.
208
+ no.
209
+ No.
210
+ NO.
211
+ nr.
212
+ Nr.
213
+ NR.
214
+ tr.
215
+ Tr.
216
+ TR.
217
+ mi.
218
+ Mi.
219
+ MI.
220
+ sta.
221
+ Sta.
222
+ STA.
223
+ sto.
224
+ Sto.
225
+ STO.
226
+ int.
227
+ Int.
228
+ INT.
229
+ inf.
230
+ Inf.
231
+ INF.
232
+ cult.
233
+ Cult.
234
+ CULT.
235
+ op.
236
+ Op.
237
+ OP.
238
+ aprox.
239
+ Aprox.
240
+ APROX.
241
+ it.
242
+ It.
243
+ IT.
244
+ ex.
245
+ Ex.
246
+ EX.
247
+ flex.
248
+ Flex.
249
+ FLEX.
250
+ ass.
251
+ Ass.
252
+ ASS.
253
+ pç.
254
+ Pç.
255
+ PÇ.
256
+ ind.
257
+ Ind.
258
+ IND.
259
+ vl.
260
+ Vl.
261
+ VL.
262
+ imp.
263
+ Imp.
264
+ IMP.
265
+ emp.
266
+ Emp.
267
+ EMP.
268
+ esq.
269
+ Esq.
270
+ ESQ.
271
+ dir.
272
+ Dir.
273
+ DIR.
274
+ ingr.
275
+ Ingr.
276
+ INGR.
277
+ pça.
278
+ Pça.
279
+ PÇA.
280
+ art.
281
+ Art.
282
+ ART.
283
+ sec.
284
+ Sec.
285
+ SEC.
286
+ a.
287
+ A.
288
+ b.
289
+ B.
290
+ c.
291
+ C.
292
+ d.
293
+ D.
294
+ e.
295
+ E.
296
+ f.
297
+ F.
298
+ g.
299
+ G.
300
+ h.
301
+ H.
302
+ i.
303
+ I.
304
+ j.
305
+ J.
306
+ k.
307
+ K.
308
+ l.
309
+ L.
310
+ m.
311
+ M.
312
+ n.
313
+ N.
314
+ o.
315
+ O.
316
+ p.
317
+ P.
318
+ q.
319
+ Q.
320
+ r.
321
+ R.
322
+ s.
323
+ S.
324
+ t.
325
+ T.
326
+ u.
327
+ U.
328
+ v.
329
+ V.
330
+ w.
331
+ W.
332
+ x.
333
+ X.
334
+ y.
335
+ Y.
336
+ z.
337
+ Z.
338
+ seg.
339
+ ter.
340
+ qua.
341
+ qui.
342
+ sex.
343
+ sab.
344
+ sáb.
345
+ dom.
346
+ Seg.
347
+ Ter.
348
+ Qua.
349
+ Qui.
350
+ Sex.
351
+ Sab.
352
+ Sáb.
353
+ Dom.
354
+ SEG.
355
+ TER.
356
+ QUA.
357
+ QUI.
358
+ SEX.
359
+ SAB.
360
+ SÁB.
361
+ DOM.
362
+ jan.
363
+ fev.
364
+ mar.
365
+ abr.
366
+ mai.
367
+ jun.
368
+ jul.
369
+ ago.
370
+ sep.
371
+ out.
372
+ nov.
373
+ dez.
374
+ Jan.
375
+ Fev.
376
+ Mar.
377
+ Abr.
378
+ Mai.
379
+ Jun.
380
+ Jul.
381
+ Ago.
382
+ Sep.
383
+ Out.
384
+ Nov.
385
+ Dez.
386
+ JAN.
387
+ FEV.
388
+ MAR.
389
+ ABR.
390
+ MAI.
391
+ JUN.
392
+ JUL.
393
+ AGO.
394
+ SET.
395
+ OUT.
396
+ NOV.
397
+ DEZ.
src/portSentencer/portSent.py ADDED
@@ -0,0 +1,242 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # portSentencer - sentenciador de texto puro para o Portugues
2
+ #
3
+ # Este programa recebe diversos arquivos de entrada em formato
4
+ # textual e gera um arquivo textual com uma sentença por linha.
5
+ #
6
+ # Opções:
7
+ #
8
+ # -h help
9
+ # -o output file
10
+ # -r replace non standart characters
11
+ # -l limit the number of characters per sentence
12
+ #
13
+ # Exemplo de utilização:
14
+ #
15
+ # portSent -o sents.txt -r -l 2048 text1.txt text2.txt
16
+ #
17
+ # Busca o texto nos arquivos 'text1.txt' e 'text2.txt',
18
+ # substitui caracteres não usuais,
19
+ # gera sentenças com limite máximo de 2048 carateres e
20
+ # salva as sentenças no arquivo 'sents.txt'
21
+ #
22
+ # last edit: 01/21/2024
23
+ # created by Lucelene Lopes - [email protected]
24
+
25
+ import sys, os
26
+
27
+ #################################################
28
+ ### Captura de argumentos da linha de comando
29
+ #################################################
30
+ def parseOptions(arguments):
31
+ # default options
32
+ output_file, input_files, replace, limit = "", [], False, 0
33
+ i = 1
34
+ while i < len(arguments):
35
+ if (arguments[i][0] == "-"):
36
+ # ajuda (help) - mostra ajuda, nada é executado
37
+ if ((arguments[i][1] == "h") and (len(arguments[i])==2)) or \
38
+ (arguments[i] == "-help"):
39
+ print("Opções:\n-h ajuda\n-o arquivo de saída", \
40
+ "-r substitui caracteres não padrão", \
41
+ "-l limite de caracteres por sentença", \
42
+ " -demais opções ignoradas, por favor execute novamente sem opção de ajuda",
43
+ "Exemplo de utilização:", \
44
+ "portSent -o sents.txt -r -l 2048 text1.txt text2.txt", \
45
+ "Busca o texto nos arquivos 'text1.txt' e 'text2.txt'", \
46
+ " substitui caracteres não usuais,", \
47
+ " gera sentenças com limite máximo de 2048 carateres e", \
48
+ " salva as sentenças no arquivo 'sents.txt'", \
49
+ sep="\n")
50
+ return None
51
+ # opção de substituição (replace) de caracteres não usuais
52
+ elif ((arguments[i][1] == "r") and (len(arguments[i])==2)) or \
53
+ (arguments[i] == "-replace"):
54
+ replace = True
55
+ i += 1
56
+ # opção de limite de tamanho de sentença (limit) - 0 para sem limite
57
+ elif ((arguments[i][1] == "l") and (len(arguments[i])==2)) or \
58
+ (arguments[i] == "-limit"):
59
+ try:
60
+ limit = eval(arguments[i+1])
61
+ i += 2
62
+ except:
63
+ print("limite de caracteres por sentença não informado - assumindo sem limite")
64
+ i += 1
65
+ # opção de arquivo de saída (um nome de arquivo)
66
+ elif ((arguments[i][1] == "o") and (len(arguments[i])==2)) or \
67
+ (arguments[i] == "-output"):
68
+ output_file = arguments[i+1]
69
+ i += 2
70
+ # opções inválidas - nada é executado
71
+ else:
72
+ print("Opção {} inválida, demais opções ignoradas, por favor execute novamente".format(arguments[i]))
73
+ return None
74
+ # arquivos de entrada (qualquer número) - só são incluídos se existirem
75
+ else:
76
+ if (os.path.isfile(arguments[i])):
77
+ input_files.append(arguments[i])
78
+ i += 1
79
+ else:
80
+ print("O arquivo {} não foi encontrado (ignorado)".format(arguments[i]))
81
+ i += 1
82
+ return [output_file, input_files, limit, replace]
83
+
84
+ #################################################
85
+ ### função stripSents - faz de fato o sentenciamento
86
+ #################################################
87
+ def stripSents(inputText, outfile, limit, replace):
88
+ def cleanPrint(sent, outfile):
89
+ # do not print empty sentences
90
+ if (sent == "") or (sent == ".") or (sent == ".."):
91
+ return 0
92
+ # remove second . in sentences ending by ..
93
+ elif (len(sent) > 2) and (sent[-3:] != "...") and (sent[-2:] == ".."):
94
+ print(sent[:-1], file=outfile)
95
+ return 1
96
+ # insert . in sentences not ending by punctuation
97
+ elif (sent[-1] not in [".", "!", "?", ":", ";"]) and \
98
+ not ((sent[-1] in ["'", '"']) and (sent[-2] in [".", "!", "?"])):
99
+ print(sent+".", file=outfile)
100
+ return 1
101
+ # remove encompassing quotations " or ' if the quotations do not appear inside the sentence
102
+ elif (sent[0] == sent[1]) and ((sent[0] == "'") or (sent[0] == '"')) and (sent.count(sent[0]) == 2):
103
+ print(sent[1:-1], file=outfile)
104
+ return 1
105
+ # otherwise print it as it is
106
+ else:
107
+ print(sent, file=outfile)
108
+ return 1
109
+ def isAbbrev(chunk, abbrev):
110
+ abbr = False
111
+ for a in abbrev:
112
+ if (chunk == a):
113
+ abbr = True
114
+ break
115
+ else:
116
+ lasts = -len(a)
117
+ if (chunk[lasts:] == a) and (not chunk[lasts-1].isalpha()):
118
+ abbr = True
119
+ break
120
+ return abbr
121
+ # the function stripSents main body
122
+ abbrev = []
123
+ infile = open("./src/portSentencer/abbrev.txt", "r")
124
+ for line in infile:
125
+ abbrev.append(line[:-1])
126
+ infile.close()
127
+ if (replace):
128
+ replaceables = [[" ", " "], \
129
+ ["—", "-"], ["–", "-"], \
130
+ ['"', '"'], \
131
+ ['“', '"'], ['”', '"'], \
132
+ ['‟', '"'], ['″', '"'], \
133
+ ['‶', '"'], ['〃', '"'], \
134
+ ['״', '"'], ['˝', '"'], \
135
+ ['ʺ', '"'], ['˶', '"'], \
136
+ ['ˮ', '"'], ['ײ', '"'], \
137
+ [" ‣", "."], [" >>", "."], [" ○", "."], [" *", "."], \
138
+ [" | ", ". "], [" .", "."], \
139
+ ["\n", " "], ["\t", " "]]
140
+ else:
141
+ replaceables = [["\n", " "], ["\t", " "]]
142
+ tmp = inputText.replace(" "," ")
143
+ for r in replaceables:
144
+ tmp = tmp.replace(r[0], r[1])
145
+ while (tmp.find(" ") != -1):
146
+ tmp = tmp.replace(" "," ")
147
+ if (tmp[0] == " "):
148
+ tmp = tmp[1:]
149
+ bagOfChunks = tmp.split(" ")
150
+ s, sent = 0, ""
151
+ if (bagOfChunks[-1] == ""):
152
+ bagOfChunks.pop()
153
+ for i in range(len(bagOfChunks)):
154
+ # if it is the last chunk, it is the end of sentence
155
+ if (i == len(bagOfChunks)-1):
156
+ sent += " " + bagOfChunks[i]
157
+ s += cleanPrint(sent[1:], outfile)
158
+ break
159
+ chunk = bagOfChunks[i]
160
+ # if there is a limit and the chunk is greater than the limit, discard it
161
+ if (limit != 0) and (len(chunk) > limit):
162
+ continue
163
+ # if there is a limit and it is reached, ends the sentence arbitrarily
164
+ elif (limit != 0) and (len(sent) + len(chunk) > limit):
165
+ s += cleanPrint(sent[1:], outfile)
166
+ sent = chunk
167
+ # if the chunk is too short
168
+ elif (len(chunk) < 3) and (len(chunk) != 0):
169
+ sent += " " + chunk
170
+ # if the chunk is empty
171
+ elif (len(chunk) == 0):
172
+ continue
173
+ # ! ? or ... always mark an end of sentence
174
+ elif (chunk[-3:] == "...") or (chunk[-1] == "!") or (chunk[-1] == "?"):
175
+ sent += " " + chunk
176
+ s += cleanPrint(sent[1:], outfile)
177
+ sent = ""
178
+ # a . : or ; followed by a lowercase chunk is not an end of sentence
179
+ elif ((chunk[-1] == ".") or (chunk[-1] == ":") or (chunk[-1] == ";")) and (bagOfChunks[i+1][0].islower()):
180
+ sent += " " + chunk
181
+ # a : or ; not followed by a lowercase chunk is an end of sentence
182
+ elif ((chunk[-1] == ":") or (chunk[-1] == ";")) and (not bagOfChunks[i+1][0].islower()):
183
+ sent += " " + chunk
184
+ s += cleanPrint(sent[1:], outfile)
185
+ sent = ""
186
+ # chunk ends with ! or ? followed by quotations that had appear before an odd number is an end of sentence
187
+ elif (chunk[-2:] in ["!'", '!"', "?'", '?"']):
188
+ sent += " " + chunk
189
+ s += cleanPrint(sent[1:], outfile)
190
+ sent = ""
191
+ elif (chunk[-2:] in [".'", '."']):
192
+ sent += " " + chunk
193
+ abbr = isAbbrev(chunk[:-1], abbrev)
194
+ if not abbr:
195
+ s += cleanPrint(sent[1:], outfile)
196
+ sent = ""
197
+ # a chunk not ending with ! ? ... ; : or . is not an end of sentence
198
+ elif (chunk[-1] != "."):
199
+ sent += " " + chunk
200
+ # chunk ending by . is either a know abbreviation (not an end of sentence), or an end of sentence
201
+ elif (chunk[-1] == "."):
202
+ abbr = isAbbrev(chunk, abbrev)
203
+ if (abbr):
204
+ sent += " " + chunk
205
+ else:
206
+ sent += " " + chunk
207
+ s += cleanPrint(sent[1:], outfile)
208
+ sent = ""
209
+ # return the number of generated sentences
210
+ return s
211
+
212
+ #################################################
213
+ ### função principal do programa - busca argumentos e chama 'stripSents' que faz de fato o sentenciamento
214
+ #################################################
215
+ def portSent():
216
+ if (len(sys.argv) == 1):
217
+ arguments = ["sents2.txt", ["relic.txt"], 0, True]
218
+ print("Assumindo default: 'sents.txt' como arquivo de saída, 'text1.txt' como arquivo de entrada, sem limite e substituições.")
219
+ else:
220
+ arguments = parseOptions(sys.argv)
221
+ if (arguments != None):
222
+ if (arguments[0] == ""):
223
+ print("Assumindo 'sents.txt' como arquivo de saída")
224
+ arguments[0] = 'sents.txt'
225
+ if (arguments[1] == []):
226
+ print("Nenhum arquivo de entrada válido - por favor corrija e tente novamente")
227
+ else:
228
+ outfile = open(arguments[0], "w")
229
+ inputText = ""
230
+ for oneInput in arguments[1]:
231
+ infile = open(oneInput, "r")
232
+ inputText += infile.read()
233
+ infile.close()
234
+ s = stripSents(inputText, outfile, arguments[2], arguments[3])
235
+ outfile.close()
236
+ print("Sentenciamento terminado com {} sentenças extraídas e salvas em {}".format(s, arguments[0]))
237
+ else:
238
+ print("Problemas com parâmetros - por favor corrija e tente novamente")
239
+
240
+ portSent()
241
+
242
+
src/portTokenizer/ADJ.tsv ADDED
The diff for this file is too large to render. See raw diff
 
src/portTokenizer/ADP.tsv ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ a a _
2
+ afora afora _
3
+ ante ante _
4
+ após após _
5
+ até até _
6
+ com com _
7
+ como como _
8
+ conforme conforme _
9
+ consoante consoante _
10
+ contra contra _
11
+ dado dado _
12
+ de de _
13
+ desde desde _
14
+ devido devido _
15
+ durante durante _
16
+ em em _
17
+ entre entre _
18
+ exceto exceto _
19
+ fora fora _
20
+ malgrado malgrado _
21
+ mediante mediante _
22
+ menos menos _
23
+ para para _
24
+ perante perante _
25
+ por por _
26
+ pra para Abbr=Yes
27
+ pró pró _
28
+ que que _
29
+ salvo salvo _
30
+ segundo segundo _
31
+ sem sem _
32
+ senão senão _
33
+ sob sob _
34
+ sobre sobre _
35
+ versus versus _
36
+ via via _
37
+ visto visto _
38
+ vs versus Abbr=Yes
src/portTokenizer/ADV.tsv ADDED
The diff for this file is too large to render. See raw diff
 
src/portTokenizer/AUX.tsv ADDED
@@ -0,0 +1,435 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ era ser Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
2
+ era ser Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
3
+ eram ser Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
4
+ eras ser Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
5
+ estada estar Gender=Fem|Number=Sing|VerbForm=Part
6
+ estadas estar Gender=Fem|Number=Plur|VerbForm=Part
7
+ estado estar Gender=Masc|Number=Sing|VerbForm=Part
8
+ estados estar Gender=Masc|Number=Plur|VerbForm=Part
9
+ estai estar Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
10
+ estais estar Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
11
+ estamos estar Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
12
+ estando estar VerbForm=Ger
13
+ estar estar Number=Sing|Person=1|VerbForm=Inf
14
+ estar estar Number=Sing|Person=3|VerbForm=Inf
15
+ estar estar VerbForm=Inf
16
+ estardes estar Number=Plur|Person=2|VerbForm=Inf
17
+ estarei estar Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
18
+ estareis estar Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
19
+ estarem estar Number=Plur|Person=3|VerbForm=Inf
20
+ estaremos estar Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
21
+ estares estar Number=Sing|Person=2|VerbForm=Inf
22
+ estaria estar Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
23
+ estaria estar Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
24
+ estariam estar Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
25
+ estarias estar Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
26
+ estarmos estar Number=Plur|Person=1|VerbForm=Inf
27
+ estará estar Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
28
+ estarás estar Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
29
+ estarão estar Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
30
+ estaríamos estar Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
31
+ estaríeis estar Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
32
+ estava estar Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
33
+ estava estar Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
34
+ estavam estar Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
35
+ estavas estar Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
36
+ esteja estar Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
37
+ esteja estar Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
38
+ esteja estar Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
39
+ estejais estar Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
40
+ estejam estar Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
41
+ estejam estar Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
42
+ estejamos estar Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
43
+ estejamos estar Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
44
+ estejas estar Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
45
+ esteve estar Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
46
+ estive estar Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
47
+ estivemos estar Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
48
+ estiver estar Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
49
+ estiver estar Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
50
+ estivera estar Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
51
+ estivera estar Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
52
+ estiveram estar Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
53
+ estiveram estar Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
54
+ estiveras estar Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
55
+ estiverdes estar Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
56
+ estiverem estar Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
57
+ estiveres estar Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
58
+ estivermos estar Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
59
+ estivesse estar Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
60
+ estivesse estar Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
61
+ estivessem estar Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
62
+ estivesses estar Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
63
+ estiveste estar Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
64
+ estivestes estar Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
65
+ estivéramos estar Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
66
+ estivéreis estar Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
67
+ estivésseis estar Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
68
+ estivéssemos estar Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
69
+ estou estar Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
70
+ está estar Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
71
+ está estar Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
72
+ estás estar Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
73
+ estávamos estar Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
74
+ estáveis estar Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
75
+ estão estar Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
76
+ foi ir Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
77
+ foi ser Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
78
+ fomos ir Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
79
+ fomos ser Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
80
+ for ir Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
81
+ for ir Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
82
+ for ser Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
83
+ for ser Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
84
+ fora ir Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
85
+ fora ir Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
86
+ fora ser Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
87
+ fora ser Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
88
+ foram ir Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
89
+ foram ir Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
90
+ foram ser Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
91
+ foram ser Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
92
+ foras ir Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
93
+ foras ser Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
94
+ fordes ir Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
95
+ fordes ser Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
96
+ forem ir Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
97
+ forem ser Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
98
+ fores ir Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
99
+ fores ser Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
100
+ formos ir Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
101
+ formos ser Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
102
+ fosse ir Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
103
+ fosse ir Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
104
+ fosse ser Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
105
+ fosse ser Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
106
+ fossem ir Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
107
+ fossem ser Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
108
+ fosses ir Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
109
+ fosses ser Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
110
+ foste ir Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
111
+ foste ser Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
112
+ fostes ir Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
113
+ fostes ser Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
114
+ fui ir Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
115
+ fui ser Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
116
+ fôramos ir Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
117
+ fôramos ser Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
118
+ fôreis ir Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
119
+ fôreis ser Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
120
+ fôsseis ir Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
121
+ fôsseis ser Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
122
+ fôssemos ir Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
123
+ fôssemos ser Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
124
+ haja haver Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
125
+ haja haver Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
126
+ haja haver Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
127
+ hajais haver Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
128
+ hajam haver Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
129
+ hajam haver Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
130
+ hajamos haver Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
131
+ hajamos haver Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
132
+ hajas haver Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
133
+ havei haver Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
134
+ haveis haver Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
135
+ havemos haver Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
136
+ havendo haver VerbForm=Ger
137
+ haver haver Number=Sing|Person=1|VerbForm=Inf
138
+ haver haver Number=Sing|Person=3|VerbForm=Inf
139
+ haver haver VerbForm=Inf
140
+ haverdes haver Number=Plur|Person=2|VerbForm=Inf
141
+ haverei haver Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
142
+ havereis haver Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
143
+ haverem haver Number=Plur|Person=3|VerbForm=Inf
144
+ haveremos haver Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
145
+ haveres haver Number=Sing|Person=2|VerbForm=Inf
146
+ haveria haver Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
147
+ haveria haver Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
148
+ haveriam haver Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
149
+ haverias haver Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
150
+ havermos haver Number=Plur|Person=1|VerbForm=Inf
151
+ haverá haver Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
152
+ haverás haver Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
153
+ haverão haver Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
154
+ haveríamos haver Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
155
+ haveríeis haver Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
156
+ havia haver Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
157
+ havia haver Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
158
+ haviam haver Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
159
+ havias haver Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
160
+ havida haver Gender=Fem|Number=Sing|VerbForm=Part
161
+ havidas haver Gender=Fem|Number=Plur|VerbForm=Part
162
+ havido haver Gender=Masc|Number=Sing|VerbForm=Part
163
+ havidos haver Gender=Masc|Number=Plur|VerbForm=Part
164
+ havíamos haver Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
165
+ havíeis haver Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
166
+ hei haver Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
167
+ houve haver Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
168
+ houve haver Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
169
+ houvemos haver Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
170
+ houver haver Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
171
+ houver haver Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
172
+ houvera haver Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
173
+ houvera haver Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
174
+ houveram haver Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
175
+ houveram haver Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
176
+ houveras haver Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
177
+ houverdes haver Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
178
+ houverem haver Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
179
+ houveres haver Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
180
+ houvermos haver Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
181
+ houvesse haver Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
182
+ houvesse haver Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
183
+ houvessem haver Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
184
+ houvesses haver Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
185
+ houveste haver Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
186
+ houvestes haver Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
187
+ houvéramos haver Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
188
+ houvéreis haver Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
189
+ houvésseis haver Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
190
+ houvéssemos haver Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
191
+ há haver Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
192
+ há haver Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
193
+ hás haver Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
194
+ hão haver Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
195
+ ia ir Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
196
+ ia ir Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
197
+ iam ir Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
198
+ ias ir Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
199
+ ida ir Gender=Fem|Number=Sing|VerbForm=Part
200
+ idas ir Gender=Fem|Number=Plur|VerbForm=Part
201
+ ide ir Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
202
+ ides ir Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
203
+ ido ir Gender=Masc|Number=Sing|VerbForm=Part
204
+ idos ir Gender=Masc|Number=Plur|VerbForm=Part
205
+ indo ir VerbForm=Ger
206
+ ir ir Number=Sing|Person=1|VerbForm=Inf
207
+ ir ir Number=Sing|Person=3|VerbForm=Inf
208
+ ir ir VerbForm=Inf
209
+ irdes ir Number=Plur|Person=2|VerbForm=Inf
210
+ irei ir Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
211
+ ireis ir Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
212
+ irem ir Number=Plur|Person=3|VerbForm=Inf
213
+ iremos ir Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
214
+ ires ir Number=Sing|Person=2|VerbForm=Inf
215
+ iria ir Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
216
+ iria ir Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
217
+ iriam ir Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
218
+ irias ir Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
219
+ irmos ir Number=Plur|Person=1|VerbForm=Inf
220
+ irá ir Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
221
+ irás ir Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
222
+ irão ir Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
223
+ iríamos ir Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
224
+ iríeis ir Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
225
+ sede ser Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
226
+ seja ser Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
227
+ seja ser Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
228
+ seja ser Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
229
+ sejais ser Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
230
+ sejam ser Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
231
+ sejam ser Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
232
+ sejamos ser Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
233
+ sejamos ser Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
234
+ sejas ser Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
235
+ sendo ser VerbForm=Ger
236
+ ser ser Number=Sing|Person=1|VerbForm=Inf
237
+ ser ser Number=Sing|Person=3|VerbForm=Inf
238
+ ser ser VerbForm=Inf
239
+ serdes ser Number=Plur|Person=2|VerbForm=Inf
240
+ serei ser Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
241
+ sereis ser Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
242
+ serem ser Number=Plur|Person=3|VerbForm=Inf
243
+ seremos ser Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
244
+ seres ser Number=Sing|Person=2|VerbForm=Inf
245
+ seria ser Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
246
+ seria ser Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
247
+ seriam ser Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
248
+ serias ser Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
249
+ sermos ser Number=Plur|Person=1|VerbForm=Inf
250
+ será ser Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
251
+ serás ser Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
252
+ serão ser Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
253
+ seríamos ser Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
254
+ seríeis ser Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
255
+ sida ser Gender=Fem|Number=Sing|VerbForm=Part
256
+ sidas ser Gender=Fem|Number=Plur|VerbForm=Part
257
+ sido ser Gender=Masc|Number=Sing|VerbForm=Part
258
+ sidos ser Gender=Masc|Number=Plur|VerbForm=Part
259
+ sois ser Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
260
+ somos ser Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
261
+ sou ser Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
262
+ são ser Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
263
+ sê ser Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
264
+ tamos estar Abbr=Yes|Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
265
+ tava estar Abbr=Yes|Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
266
+ tavam estar Abbr=Yes|Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
267
+ tem ter Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
268
+ tem ter Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
269
+ temos ter Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
270
+ tende ter Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
271
+ tendes ter Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
272
+ tendo ter VerbForm=Ger
273
+ tenha ter Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
274
+ tenha ter Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
275
+ tenha ter Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
276
+ tenhais ter Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
277
+ tenham ter Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
278
+ tenham ter Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
279
+ tenhamos ter Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
280
+ tenhamos ter Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
281
+ tenhas ter Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
282
+ tenho ter Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
283
+ tens ter Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
284
+ ter ter Number=Sing|Person=1|VerbForm=Inf
285
+ ter ter Number=Sing|Person=3|VerbForm=Inf
286
+ ter ter VerbForm=Inf
287
+ terdes ter Number=Plur|Person=2|VerbForm=Inf
288
+ terei ter Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
289
+ tereis ter Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
290
+ terem ter Number=Plur|Person=3|VerbForm=Inf
291
+ teremos ter Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
292
+ teres ter Number=Sing|Person=2|VerbForm=Inf
293
+ teria ter Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
294
+ teria ter Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
295
+ teriam ter Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
296
+ terias ter Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
297
+ termos ter Number=Plur|Person=1|VerbForm=Inf
298
+ terá ter Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
299
+ terás ter Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
300
+ terão ter Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
301
+ teríamos ter Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
302
+ teríeis ter Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
303
+ teve ter Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
304
+ tida ter Gender=Fem|Number=Sing|VerbForm=Part
305
+ tidas ter Gender=Fem|Number=Plur|VerbForm=Part
306
+ tido ter Gender=Masc|Number=Sing|VerbForm=Part
307
+ tidos ter Gender=Masc|Number=Plur|VerbForm=Part
308
+ tinha ter Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
309
+ tinha ter Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
310
+ tinham ter Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
311
+ tinhas: ter Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
312
+ tive ter Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
313
+ tivemos ter Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
314
+ tiver ter Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
315
+ tiver ter Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
316
+ tivera ter Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
317
+ tivera ter Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
318
+ tiveram ter Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
319
+ tiveram ter Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
320
+ tiveras ter Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
321
+ tiverdes ter Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
322
+ tiverem ter Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
323
+ tiveres ter Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
324
+ tivermos ter Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
325
+ tivesse ter Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
326
+ tivesse ter Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
327
+ tivessem ter Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
328
+ tivesses ter Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
329
+ tiveste ter Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
330
+ tivestes ter Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
331
+ tivéramos ter Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
332
+ tivéreis ter Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
333
+ tivésseis ter Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
334
+ tivéssemos ter Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
335
+ tá estar Abbr=Yes|Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
336
+ tão estar Abbr=Yes|Abbr=Yes|Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
337
+ têm ter Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
338
+ tínhamos ter Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
339
+ tínheis ter Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
340
+ tô estar Abbr=Yes|Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
341
+ vades ir Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
342
+ vai ir Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
343
+ vai ir Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
344
+ vais ir Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
345
+ vamo ir Abbr=Yes|Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
346
+ vamo ir Abbr=Yes|Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
347
+ vamo ir Abbr=Yes|Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
348
+ vamos ir Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
349
+ vamos ir Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
350
+ vamos ir Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
351
+ veio vir Mood=Ind|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
352
+ vem vir Mood=Imp|Number=Sing|Person=2|VerbForm=Fin
353
+ vem vir Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
354
+ venha vir Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
355
+ venha vir Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
356
+ venha vir Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
357
+ venhais vir Mood=Sub|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
358
+ venham vir Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
359
+ venham vir Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
360
+ venhamos vir Mood=Imp|Number=Plur|Person=1|VerbForm=Fin
361
+ venhamos vir Mood=Sub|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
362
+ venhas vir Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
363
+ venho vir Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
364
+ vens: vir Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
365
+ viemos vir Mood=Ind|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
366
+ vier vir Mood=Sub|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
367
+ vier vir Mood=Sub|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
368
+ viera vir Mood=Ind|Number=Sing|Person=1|Tense=Pqp|VerbForm=Fin
369
+ viera vir Mood=Ind|Number=Sing|Person=3|Tense=Pqp|VerbForm=Fin
370
+ vieram vir Mood=Ind|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
371
+ vieram vir Mood=Ind|Number=Plur|Person=3|Tense=Pqp|VerbForm=Fin
372
+ vieras vir Mood=Ind|Number=Sing|Person=2|Tense=Pqp|VerbForm=Fin
373
+ vierdes vir Mood=Sub|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
374
+ vierem vir Mood=Sub|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
375
+ vieres vir Mood=Sub|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
376
+ viermos vir Mood=Sub|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
377
+ viesse vir Mood=Sub|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
378
+ viesse vir Mood=Sub|Number=Sing|Person=3|Tense=Past|VerbForm=Fin
379
+ viessem vir Mood=Sub|Number=Plur|Person=3|Tense=Past|VerbForm=Fin
380
+ viesses vir Mood=Sub|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
381
+ vieste vir Mood=Ind|Number=Sing|Person=2|Tense=Past|VerbForm=Fin
382
+ viestes vir Mood=Ind|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
383
+ vim vir Mood=Ind|Number=Sing|Person=1|Tense=Past|VerbForm=Fin
384
+ vimos vir Mood=Ind|Number=Plur|Person=1|Tense=Pres|VerbForm=Fin
385
+ vinda vir Gender=Fem|Number=Sing|VerbForm=Part
386
+ vindas vir Gender=Fem|Number=Plur|VerbForm=Part
387
+ vinde vir Mood=Imp|Number=Plur|Person=2|VerbForm=Fin
388
+ vindes vir Mood=Ind|Number=Plur|Person=2|Tense=Pres|VerbForm=Fin
389
+ vindo vir Gender=Masc|Number=Sing|VerbForm=Part
390
+ vindo vir VerbForm=Ger
391
+ vindos vir Gender=Masc|Number=Plur|VerbForm=Part
392
+ vinha vir Mood=Ind|Number=Sing|Person=1|Tense=Imp|VerbForm=Fin
393
+ vinha vir Mood=Ind|Number=Sing|Person=3|Tense=Imp|VerbForm=Fin
394
+ vinham vir Mood=Ind|Number=Plur|Person=3|Tense=Imp|VerbForm=Fin
395
+ vinhas: vir Mood=Ind|Number=Sing|Person=2|Tense=Imp|VerbForm=Fin
396
+ vir vir Number=Sing|Person=1|VerbForm=Inf
397
+ vir vir Number=Sing|Person=3|VerbForm=Inf
398
+ vir vir VerbForm=Inf
399
+ virdes vir Number=Plur|Person=2|VerbForm=Inf
400
+ virei vir Mood=Ind|Number=Sing|Person=1|Tense=Fut|VerbForm=Fin
401
+ vireis vir Mood=Ind|Number=Plur|Person=2|Tense=Fut|VerbForm=Fin
402
+ virem vir Number=Plur|Person=3|VerbForm=Inf
403
+ viremos vir Mood=Ind|Number=Plur|Person=1|Tense=Fut|VerbForm=Fin
404
+ vires vir Number=Sing|Person=2|VerbForm=Inf
405
+ viria vir Mood=Cnd|Number=Sing|Person=1|VerbForm=Fin
406
+ viria vir Mood=Cnd|Number=Sing|Person=3|VerbForm=Fin
407
+ viriam vir Mood=Cnd|Number=Plur|Person=3|VerbForm=Fin
408
+ virias vir Mood=Cnd|Number=Sing|Person=2|VerbForm=Fin
409
+ virmos vir Number=Plur|Person=1|VerbForm=Inf
410
+ virá vir Mood=Ind|Number=Sing|Person=3|Tense=Fut|VerbForm=Fin
411
+ virás vir Mood=Ind|Number=Sing|Person=2|Tense=Fut|VerbForm=Fin
412
+ virão vir Mood=Ind|Number=Plur|Person=3|Tense=Fut|VerbForm=Fin
413
+ viríamos vir Mood=Cnd|Number=Plur|Person=1|VerbForm=Fin
414
+ viríeis vir Mood=Cnd|Number=Plur|Person=2|VerbForm=Fin
415
+ viéramos vir Mood=Ind|Number=Plur|Person=1|Tense=Pqp|VerbForm=Fin
416
+ viéreis vir Mood=Ind|Number=Plur|Person=2|Tense=Pqp|VerbForm=Fin
417
+ viésseis vir Mood=Sub|Number=Plur|Person=2|Tense=Past|VerbForm=Fin
418
+ viéssemos vir Mood=Sub|Number=Plur|Person=1|Tense=Past|VerbForm=Fin
419
+ vou ir Mood=Ind|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
420
+ vá ir Mood=Imp|Number=Sing|Person=3|VerbForm=Fin
421
+ vá ir Mood=Sub|Number=Sing|Person=1|Tense=Pres|VerbForm=Fin
422
+ vá ir Mood=Sub|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
423
+ vás ir Mood=Sub|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
424
+ vão ir Mood=Imp|Number=Plur|Person=3|VerbForm=Fin
425
+ vão ir Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
426
+ vão ir Mood=Sub|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
427
+ vêm vir Mood=Ind|Number=Plur|Person=3|Tense=Pres|VerbForm=Fin
428
+ vínhamos vir Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
429
+ vínheis vir Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
430
+ é ser Mood=Ind|Number=Sing|Person=3|Tense=Pres|VerbForm=Fin
431
+ éramos ser Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
432
+ éreis ser Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
433
+ és ser Mood=Ind|Number=Sing|Person=2|Tense=Pres|VerbForm=Fin
434
+ íamos ir Mood=Ind|Number=Plur|Person=1|Tense=Imp|VerbForm=Fin
435
+ íeis ir Mood=Ind|Number=Plur|Person=2|Tense=Imp|VerbForm=Fin
src/portTokenizer/CCONJ.tsv ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ como como _
2
+ contudo contudo _
3
+ e e _
4
+ enquanto enquanto _
5
+ entretanto entretanto _
6
+ então então _
7
+ já já _
8
+ logo logo _
9
+ mas mas _
10
+ nem nem _
11
+ ora ora _
12
+ ou ou _
13
+ pois pois _
14
+ porquanto porquanto _
15
+ porque porque _
16
+ portanto portanto _
17
+ porém porém _
18
+ quando quando _
19
+ quanto quanto _
20
+ que que _
21
+ quer quer _
22
+ seja seja _
23
+ senão senão _
24
+ tanto tanto _
25
+ todavia todavia _