via_demo.html
HTML document, ASCII text, with very long lines (738)
1<!DOCTYPE html> 2<html lang="en"> 3<head> 4<meta charset="UTF-8"> 5<!-- 6VGG Image Annotator (via) 7www.robots.ox.ac.uk/~vgg/software/via/ 8 9Copyright (c) 2016-2018, Abhishek Dutta, Visual Geometry Group, Oxford University and VIA Contributors.. 10All rights reserved. 11 12Redistribution and use in source and binary forms, with or without 13modification, are permitted provided that the following conditions are met: 14 15Redistributions of source code must retain the above copyright notice, this 16list of conditions and the following disclaimer. 17Redistributions in binary form must reproduce the above copyright notice, 18this list of conditions and the following disclaimer in the documentation 19and/or other materials provided with the distribution. 20THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30POSSIBILITY OF SUCH DAMAGE. 31--> 32<title>VGG Image Annotator</title> 33<meta name="author" content="Abhishek Dutta"> 34<meta name="description" content="VIA is a standalone image annotator application packaged as a single HTML file (< 400 KB) that runs on most modern web browsers."> 35 36<!-- 37Development of VIA is supported by the EPSRC programme grant 38Seebibyte: Visual Search for the Era of Big Data (EP/M013774/1). 39Using Google Analytics, we record the usage of this application. 40This data is used in reporting of this programme grant. 41 42If you do not wish to share this data, you can safely remove the 43javascript code below. 44--> 45<script type="text/javascript"> 46(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ 47(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), 48m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) 49})(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); 50ga('create', 'UA-20555581-2', 'auto'); 51ga('set', 'page', 'via-2.0.0.html'); 52ga('send', 'pageview'); 53</script> 54 55<!-- START: Contents of file: via.css--> 56<style> 57/* 58CSS style definitions for VIA 2.x.y 59http://www.robots.ox.ac.uk/~vgg/software/via/ 60Author: Abhishek Dutta <adutta@robots.ox.ac.uk> 61Date: moved from index.html to via.css on 13 June 2019 62*/ 63 64body { min-width:200px; padding:0; margin:0; font-family:sans-serif; } 65* { box-sizing: border-box; } 66input[type=text] { border:1px solid #cccccc; margin:0.6rem 0; padding:0.2rem 0.4rem; } 67a { text-decoration:none; } 68textarea { border:1px solid #cccccc; margin:0.6rem 0; padding:0.2rem 0.4rem; } 69 70/* Top panel : #navbar, #toolbar */ 71.top_panel { font-size:0.9rem; display:block; background-color:#212121; color:#ffffff; z-index:1001; margin-bottom:1rem;} 72 73/* Navigation menu bar that appear at the top */ 74.menubar { display:inline-block; height:1.8rem; } /* height needed to avoid extra bottom border */ 75.menubar a:link { color:#eeeeee; text-decoration:none; } 76.menubar a:visited { color:#eeeeee; text-decoration:none; } 77.menubar ul { display:block; padding:0; margin:0; } 78.menubar li { display:inline; float:left; padding:0.45rem 1rem; } 79.menubar li:hover { background-color:#616161; cursor:default; } 80 81.menubar li ul { display:none; background-color:#212121; border:1px solid #616161; min-width:10rem; position:absolute; z-index:100; margin:0.4rem -1rem;} 82.menubar li ul li { display:block; float:none; color:#eeeeee; margin:0; padding:0.6rem 1rem; } 83.menubar li ul li:hover { cursor:pointer; } 84.menubar li ul li.submenu_divider { margin:0 0.4rem; padding:0; height:1px; border-bottom:1px solid #424242; } 85.menubar li:hover ul { display:block; } 86 87/* toolbar containing small icons for tools */ 88.toolbar { display:inline-block; margin-left:1rem; } 89.toolbar svg { fill:white; margin: 0.2rem 0.1rem; height:1.2rem; -moz-user-select:none; -webkit-user-select:none; -ms-user-select:none;} 90.toolbar svg:hover { fill:yellow; cursor:pointer; } 91.toolbar svg:active { fill:white; } 92.toolbar ul { display:inline-block; padding:0.2rem; margin:0; } 93.toolbar li { display:inline; float:left; padding:0rem 0.3rem; border:1px solid white;} /* main menu items */ 94.toolbar li:hover { color:red; cursor:pointer; } 95 96/* Middle panel: containing #image_panel, #leftsidebar */ 97.middle_panel { display:table; table-layout:fixed; width:100%; z-index:1; padding:0;} 98#leftsidebar { display:none; z-index:10; vertical-align:top;} 99#display_area { display:table-cell; width:100%; z-index:1; margin:0; padding-left:1em; vertical-align:top; } 100/* layers of canvas */ 101#image_panel { position:relative; outline:none; } 102#image_panel img { visibility:hidden; opacity:0; position:absolute; top:0px; left:0px; width:100%; height:100%; outline:none; } 103#image_panel canvas { position:absolute; top:0px; left:0px; outline:none;} 104#image_panel .visible { visibility:visible !important; opacity:1 !important; } 105#image_panel label>img { visibility:visible; opacity:1; position:relative; width:auto; height:4em; outline:none; } 106 107/* image buffer 108#image_panel .fadein { visibility:visible; opacity:1; transition: visibility 0s linear 0s, opacity 300ms; } 109#image_panel .fadeout { visibility:hidden; opacity:0; transition: visibility 0s linear 300ms, opacity 300ms; } 110*/ 111 112/* image grid view */ 113#image_grid_panel { position:relative; margin:0; padding:0; width:100%; } 114#image_grid_panel #image_grid_toolbar { display:block; font-size:small; padding:0.5rem 0;} 115#image_grid_panel #image_grid_toolbar select { font-size:small; } 116#image_grid_panel #image_grid_toolbar .tool { display:inline; margin:0 0.5rem;} 117#image_grid_panel #image_grid_group_panel { font-size:small; } 118#image_grid_panel #image_grid_group_panel select { font-size:small; } 119#image_grid_panel #image_grid_group_panel .image_grid_group_toolbar { display:inline; margin-left: 2rem;} 120#image_grid_panel #image_grid_group_panel .image_grid_group_toolbar select { margin:0 0.2rem; padding:0; font-size:small;} 121 122#image_grid_panel #image_grid_nav { display:inline; font-size:small; padding-left:0.5rem; margin-top:0.2rem; } 123#image_grid_panel #image_grid_nav span { margin: 0 0.2rem; } 124#image_grid_panel #image_grid_content { position:relative; overflow:hidden; margin:0; padding:0; outline:none; } 125#image_grid_panel #image_grid_content #image_grid_content_img img { margin:0.3em; padding:0; border:0.2em solid #ffffff; outline:0.1em solid #0066ff;} 126#image_grid_panel #image_grid_content #image_grid_content_img .not_sel { opacity:0.6; outline:none; } 127#image_grid_panel #image_grid_content #image_grid_content_img { position:absolute; top:0; left:0; width:100%; height:100%; } 128#image_grid_panel #image_grid_content #image_grid_content_rshape { position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; } 129#image_grid_panel #image_grid_content img { float:left; margin:0; } 130 131#leftsidebar_collapse_panel { display:none; position:relative; z-index:10; vertical-align:top; } 132#leftsidebar_show_button { font-size:large; margin-left:0.1rem; } 133#leftsidebar_show_button:hover { color:red; cursor: pointer; } 134 135/* Left sidebar accordion */ 136button.leftsidebar_accordion { font-size:large; background-color:#f2f2f2; cursor:pointer; padding:0.5em 0.5em; width:100%; text-align:left; border:0; outline:none; } 137button.leftsidebar_accordion:focus { outline: none; } 138button.leftsidebar_accordion.active, button.leftsidebar_accordion:hover { background-color: #e6e6e6; } 139button.leftsidebar_accordion:after { content:'\02795'; color:#4d4d4d; float:right; } 140button.leftsidebar_accordion.active:after { content: '\2796'; } 141.leftsidebar_accordion_panel { display:none; padding:0 0.5em; font-size:small; border-right:2px solid #f2f2f2; border-bottom:2px solid #f2f2f2; } 142.leftsidebar_accordion_panel.show { display:block; } 143 144/* Keyboard shortcut panel */ 145.leftsidebar_accordion_panel table { border-collapse:collapse; } 146.leftsidebar_accordion_panel td { border:1px solid #f2f2f2; padding:0.2rem 0.4rem; } 147 148/* buttons */ 149.button_panel { display:inline-block; width:100%; margin:0.2rem 0; } 150.button_panel .text_button, .text_button { color: #0000ff; padding: 0.2rem 0.2rem; -moz-user-select:none; -webkit-user-select:none; -ms-user-select:none; } 151.button_panel .flush_right { float:right; } 152.button_panel .text_button:hover, .text_button:hover { cursor:pointer; } 153.button_panel .text_button:active, .text_button:active { color: #000000; } 154.button_panel .active { border-bottom:1px solid black; } 155.button_panel .button { display:inline-block; padding:0.35rem 0.5rem; margin:0 0.05rem; cursor:pointer; background-color:#cccccc; border-radius:0.2rem; -moz-user-select:none; -webkit-user-select:none; -ms-user-select:none; } 156.button_panel .button:hover { background-color:black; color:white; } 157 158/* Attributes properties: name, description, type, ... */ 159#attribute_properties { display:table; width:100%; border-collapse:collapse; margin:1rem 0; border:1px solid #cccccc; } 160#attribute_properties .property { display:table-row;} 161#attribute_properties .property span { display:table-cell; padding: 0.2rem 0.4rem; } 162#attribute_properties .property span input { width: 100%; border:1px solid #cccccc; margin: 0;} 163#attribute_properties .property span input:focus { border:1px solid black; } 164#attribute_properties .property span select { width: 100%; border:1px solid #cccccc; margin: 0;} 165 166/* Attributes options: options for attribute type={checkbox,radio,...} */ 167#attribute_options { display:table; width:100%; border-collapse:collapse; margin:1rem 0; border:1px solid #cccccc; table-layout:fixed; } 168#attribute_options .new_option_id_entry { display:inline-block; padding:1rem 0.2rem; } 169#attribute_options .new_option_id_entry input {border:none; border-bottom:1px solid #cccccc; margin: 0; font-size: 0.8rem;} 170#attribute_options .property { display:table-row;} 171#attribute_options .property span { display:table-cell; padding: 0.2rem 0.2rem; font-weight:bold; } 172#attribute_options .property input { display:table-cell; width:94%; border:none; border-bottom:1px solid #cccccc; margin: 0; font-size: 0.8rem;} 173#attribute_options .property input:focus { border-bottom:1px solid #000000; background-color:#f2f2f2; color:#000000; } 174#attribute_options .property span input[type=checkbox] { vertical-align:middle; } 175#attribute_options .property span input[type=radio] { vertical-align:middle; } 176 177/* overlay panel used to gather user inputs before invoking a function using invoke_with_user_inputs() */ 178#user_input_panel { position:fixed; display:none; width:100%; height:100%; top:0; left:0; right:0; bottom:0; background-color: rgba(0,0,0,0.6); z-index:1002; } 179#user_input_panel .content { position:fixed; background-color:white; top:50%; left:50%; transform:translate(-50%,-50%); -webkit-transform: translate(-50%, -50%); -moz-transform: translate(-50%, -50%); -o-transform: translate(-50%, -50%); -ms-transform: translate(-50%, -50%); padding:2rem 4rem;} 180#user_input_panel .content .title { font-size:large; font-weight:bold; } 181#user_input_panel .content .user_inputs { display:table; width:100%; border-collapse:collapse;} 182#user_input_panel .content .user_inputs .row { display:table-row; } 183#user_input_panel .content .user_inputs .cell { display:table-cell; padding:1rem 0.5rem; vertical-align:middle; border:1px solid #f2f2f2; } 184#user_input_panel .content .user_confirm { display:table; width:100%; text-align:center; margin:2rem 0;} 185#user_input_panel .content .user_confirm .ok { display:table-cell; width:48%; } 186#user_input_panel .content .user_confirm .cancel { display:table-cell; width:48%; } 187#user_input_panel .content .warning { color:red; } 188 189/* Attribute editor */ 190#annotation_editor_panel { position:fixed; display:none; width:100%; left:0; bottom:0; background-color:white; border-top:2px solid #cccccc; padding:0.2em 1em; overflow:auto; z-index:1001; box-shadow: 0 0 1em #cccccc;} 191#annotation_editor { display:table; margin-bottom:3em; border-collapse:collapse; font-size:inherit; position: absolute; background-color:white; } 192#annotation_editor .row { display:table-row; } 193#annotation_editor .highlight .col { background-color:#e6e6e6;} 194 195#annotation_editor .col { display:table-cell; padding:0.4em 0.6em; border:1px solid #000000; vertical-align:middle; font-size:inherit; } 196#annotation_editor .header { font-weight:bold; } 197#annotation_editor .id { font-weight:bold; } 198#annotation_editor .col input[type=checkbox] { vertical-align:middle; } 199#annotation_editor .col input[type=radio] { vertical-align:middle; font-size:inherit; } 200#annotation_editor .col label { vertical-align:middle; font-size:inherit; } 201#annotation_editor .col textarea { border:0.1em solid #cccccc; padding:0; margin:0; font-size:inherit; background-color:#ffffff; } 202#annotation_editor .col textarea:focus { border:0.1em dashed #cccccc; } 203#annotation_editor .col span { display:block; } 204#annotation_editor .col horizontal_container { display:inline-block; } 205 206#annotation_editor .col .img_options { display:inline; } 207#annotation_editor .col .img_options .imrow { display:block; } 208#annotation_editor .col .img_options span { display:inline-block; margin: 0.2rem 0.4rem;} 209#annotation_editor .col .img_options span img { height:4em; } 210#annotation_editor .col .img_options p { margin:0; padding:0; font-size:inherit; } 211#annotation_editor .col .img_options input[type=radio] { display:none; } 212#annotation_editor .col .img_options input[type=radio] + label { display:block; cursor:pointer; text-align:center;} 213#annotation_editor .col .img_options input[type=radio]:checked + label { border: 0.1em solid black; background-color:#cccccc; cursor:default; font-size:inherit; } 214 215#project_info_panel { display:table; border-collapse:collapse; font-size:0.8rem; } 216#project_info_panel .row { display:table-row; } 217#project_info_panel .col { display:table-cell; padding:0.4rem 0.1rem; border:none; } 218#project_info_panel .col input[type=text] { font-size:0.8rem; border:none; border-bottom:1px solid #cccccc; margin: 0; width:100%;} 219#project_info_panel .col input:focus { border-bottom:1px solid #000000; background-color:#f2f2f2; color:#000000; } 220 221/* Region shape selection panel inside leftsidebar */ 222ul.region_shape { font-size:xx-large; list-style-type:none; overflow:hidden; padding:0.4em 0; margin:0; } 223ul.region_shape li { float:left; padding:0 0.2em; fill:#ffffff; stroke:#000000; } 224ul.region_shape li:hover { cursor:pointer; fill:#ffffff; stroke:#ff0000; } 225ul.region_shape .selected { fill:#ffffff; stroke:#ff0000; } 226 227/* cursor coordinates inside region shape selection panel in leftsidebar */ 228#region_info { font-size:0.8em; margin-bottom:0.4em; } 229 230/* Loaded image list shown in leftsidebar panel */ 231#img_fn_list { display:none; font-size:small; overflow:scroll; min-height:10rem; max-height:25rem; } 232#img_fn_list ul { position:relative; line-height:1.3em; margin:0; padding:0; list-style-type:none;} 233#img_fn_list li { white-space:nowrap; display:block; padding:0 0.4rem; } 234#img_fn_list li:hover { background-color:#d5e5ff; cursor:pointer; } 235#img_fn_list .error { color:red; } 236#img_fn_list .sel { border-left:0.2rem solid black !important; font-weight:bold; } 237#img_fn_list .buffered { border-left:0.2rem solid #cccccc; } 238 239#message_panel { display:block; width:100%; position:fixed; bottom:0px; z-index:9999; text-align:center; } 240#message_panel .content { display:inline; margin:auto; background-color:#000000; color:#ffff00; font-size:small; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; line-height:2rem; padding: 0.5rem 2rem;} 241 242.text_panel { display:none; margin:auto; font-size:medium; line-height:1.3em; margin: 0; max-width:700px; } 243.text_panel li { margin:1em 0; text-align:left; } 244.text_panel p { text-align:left; } 245 246.svg_button:hover { cursor:pointer; } 247 248/* Loading spinbar */ 249.loading_spinbox { display:inline-block; border:0.4em solid #cccccc; border-radius:50%; border-top:0.4em solid black; border-bottom:0.4em solid black;-webkit-animation:spin 2s linear infinite; animation:spin 2s linear infinite; } 250@-webkit-keyframes spin { 0% { -webkit-transform: rotate(0deg); } 100% { -webkit-transform: rotate(360deg); } } 251@keyframes spin { 0% { transform: rotate(0deg); } 100% { transform: rotate(360deg); } } 252 253#invisible_file_input { width:0.1px; height:0.1px; opacity:0; overflow:hidden; position:absolute; z-index:-1; } 254 255.display_none { display:none !important; } 256.display_block { display:block !important; } 257 258/* project settings */ 259#settings_panel { font-size:1rem; border-collapse:collapse; width:95%; } 260#settings_panel a { border: 1px solid #f2f2f2; } 261#settings_panel .row { display:table-row; border-bottom:1px solid #f2f2f2; } 262#settings_panel .variable { display:table-cell; width:60%; padding:0.5rem 0.5rem; } 263#settings_panel .variable div { display:block; } 264#settings_panel .variable .name { } 265#settings_panel .variable .desc { font-size:0.7em; color:#808080; padding:0.2rem 0rem; } 266#settings_panel .value { display:table-cell; vertical-align:middle; padding-left:1rem; } 267 268/* page {about, help, file not found, etc.} */ 269.display_area_content { } /* this class is used to clear the display area content */ 270.narrow_page_content li { font-size:0.9rem; margin: 0.4rem 0; } 271.narrow_page_content { width:60%; } 272 273.force_small_font { font-size:small !important; } 274.key { font-family:monospace; padding:1px 6px; background:linear-gradient(to bottom,#f0f0f0,#fcfcfc);; border:1px solid #e0e0e0; white-space:nowrap; color:#303030; border-bottom-width:2px; border-radius:3px; font-size:1.2em; } 275</style> 276<!-- END: Contents of file: via.css--> 277</head> 278 279<body onload="_via_init()" onresize="_via_update_ui_components()"> 280<!-- 281SVG icon set definitions 282Material icons downloaded from https://material.io/icons 283--> 284<svg style="display:none;" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"> 285<defs> 286<symbol id="via_logo"> 287<!-- Logo designed by Abhishek Dutta <adutta@robots.ox.ac.uk>, May 2018 --> 288<title>VGG Image Annotator Logo</title> 289<rect width="400" height="160" x="0" y="0" fill="#212121"></rect> 290 291<text x="56" y="130" font-family="Serif" font-size="100" fill="white">V</text> 292<text x="180" y="130" font-family="Serif" font-size="100" fill="white">I</text> 293<text x="270" y="130" font-family="Serif" font-size="100" fill="white">A</text> 294 295<rect width="80" height="100" x="52" y="40" stroke="yellow" fill="none" stroke-width="2"></rect> 296<text x="72" y="30" font-family="'Comic Sans MS', cursive, sans-serif" font-size="18" fill="yellow">VGG</text> 297 298<rect width="50" height="100" x="175" y="45" stroke="yellow" fill="none" stroke-width="2"></rect> 299<text x="175" y="35" font-family="'Comic Sans MS', cursive, sans-serif" font-size="18" fill="yellow">Image</text> 300 301<rect width="80" height="100" x="265" y="40" stroke="yellow" fill="none" stroke-width="2"></rect> 302<text x="265" y="30" font-family="'Comic Sans MS', cursive, sans-serif" font-size="18" fill="yellow">Annotator</text> 303</symbol> 304<symbol id="shape_rectangle"> 305<title>Rectangular region shape</title> 306<rect width="20" height="12" x="6" y="10" stroke-width="2"></rect> 307</symbol> 308<symbol id="shape_circle"> 309<title>Circular region shape</title> 310<circle r="10" cx="16" cy="16" stroke-width="2"></circle> 311</symbol> 312<symbol id="shape_ellipse"> 313<title>Elliptical region shape</title> 314<ellipse rx="12" ry="8" cx="16" cy="16" stroke-width="2"></ellipse> 315</symbol> 316<symbol id="shape_polygon"> 317<title>Polygon region shape</title> 318<path d="M 15.25,2.2372 3.625,11.6122 6,29.9872 l 20.75,-9.625 2.375,-14.75 z" stroke-width="2"></path> 319</symbol> 320<symbol id="shape_point"> 321<title>Point region shape</title> 322<circle r="3" cx="16" cy="16" stroke-width="2"></circle> 323</symbol> 324<symbol id="shape_polyline"> 325<title>Polyline region shape</title> 326<path d="M 2,12 10,24 18,12 24,18" stroke-width="2"></path> 327<circle r="1" cx="2" cy="12" stroke-width="2"></circle> 328<circle r="1" cx="10" cy="24" stroke-width="2"></circle> 329<circle r="1" cx="18" cy="12" stroke-width="2"></circle> 330<circle r="1" cx="24" cy="18" stroke-width="2"></circle> 331</symbol> 332 333<!-- Material icons downloaded from https://material.io/icons --> 334<symbol id="icon_settings"> 335<path d="M19.43 12.98c.04-.32.07-.64.07-.98s-.03-.66-.07-.98l2.11-1.65c.19-.15.24-.42.12-.64l-2-3.46c-.12-.22-.39-.3-.61-.22l-2.49 1c-.52-.4-1.08-.73-1.69-.98l-.38-2.65C14.46 2.18 14.25 2 14 2h-4c-.25 0-.46.18-.49.42l-.38 2.65c-.61.25-1.17.59-1.69.98l-2.49-1c-.23-.09-.49 0-.61.22l-2 3.46c-.13.22-.07.49.12.64l2.11 1.65c-.04.32-.07.65-.07.98s.03.66.07.98l-2.11 1.65c-.19.15-.24.42-.12.64l2 3.46c.12.22.39.3.61.22l2.49-1c.52.4 1.08.73 1.69.98l.38 2.65c.03.24.24.42.49.42h4c.25 0 .46-.18.49-.42l.38-2.65c.61-.25 1.17-.59 1.69-.98l2.49 1c.23.09.49 0 .61-.22l2-3.46c.12-.22.07-.49-.12-.64l-2.11-1.65zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"></path> 336</symbol> 337<symbol id="icon_save"> 338<path d="M17 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V7l-4-4zm-5 16c-1.66 0-3-1.34-3-3s1.34-3 3-3 3 1.34 3 3-1.34 3-3 3zm3-10H5V5h10v4z"></path> 339</symbol> 340<symbol id="icon_open"> 341<path d="M20 6h-8l-2-2H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V8c0-1.1-.9-2-2-2zm0 12H4V8h16v10z"></path> 342</symbol> 343<symbol id="icon_gridon"> 344<path d="M20 2H4c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM8 20H4v-4h4v4zm0-6H4v-4h4v4zm0-6H4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4zm6 12h-4v-4h4v4zm0-6h-4v-4h4v4zm0-6h-4V4h4v4z"></path> 345</symbol> 346<symbol id="icon_gridoff"> 347<path d="M8 4v1.45l2 2V4h4v4h-3.45l2 2H14v1.45l2 2V10h4v4h-3.45l2 2H20v1.45l2 2V4c0-1.1-.9-2-2-2H4.55l2 2H8zm8 0h4v4h-4V4zM1.27 1.27L0 2.55l2 2V20c0 1.1.9 2 2 2h15.46l2 2 1.27-1.27L1.27 1.27zM10 12.55L11.45 14H10v-1.45zm-6-6L5.45 8H4V6.55zM8 20H4v-4h4v4zm0-6H4v-4h3.45l.55.55V14zm6 6h-4v-4h3.45l.55.54V20zm2 0v-1.46L17.46 20H16z"></path> 348</symbol> 349<symbol id="icon_next"> 350<path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"></path> 351</symbol> 352<symbol id="icon_prev"> 353<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"></path> 354</symbol> 355<symbol id="icon_list"> 356<path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"></path> 357</symbol> 358<symbol id="icon_zoomin"> 359<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path> 360<path d="M12 10h-2v2H9v-2H7V9h2V7h1v2h2v1z"/> 361</symbol> 362<symbol id="icon_zoomout"> 363<path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14zM7 9h5v1H7z"></path> 364</symbol> 365<symbol id="icon_copy"> 366<path d="M16 1H4c-1.1 0-2 .9-2 2v14h2V3h12V1zm3 4H8c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h11c1.1 0 2-.9 2-2V7c0-1.1-.9-2-2-2zm0 16H8V7h11v14z"></path> 367</symbol> 368<symbol id="icon_paste"> 369<path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path> 370</symbol> 371<symbol id="icon_pasten"> 372<path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path> 373<text x="8" y="18">n</text> 374</symbol> 375<symbol id="icon_pasteundo"> 376<path d="M19 2h-4.18C14.4.84 13.3 0 12 0c-1.3 0-2.4.84-2.82 2H5c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm-7 0c.55 0 1 .45 1 1s-.45 1-1 1-1-.45-1-1 .45-1 1-1zm7 18H5V4h2v3h10V4h2v16z"></path> 377<text x="8" y="18">x</text> 378</symbol> 379<symbol id="icon_selectall"> 380<path d="M3 5h2V3c-1.1 0-2 .9-2 2zm0 8h2v-2H3v2zm4 8h2v-2H7v2zM3 9h2V7H3v2zm10-6h-2v2h2V3zm6 0v2h2c0-1.1-.9-2-2-2zM5 21v-2H3c0 1.1.9 2 2 2zm-2-4h2v-2H3v2zM9 3H7v2h2V3zm2 18h2v-2h-2v2zm8-8h2v-2h-2v2zm0 8c1.1 0 2-.9 2-2h-2v2zm0-12h2V7h-2v2zm0 8h2v-2h-2v2zm-4 4h2v-2h-2v2zm0-16h2V3h-2v2zM7 17h10V7H7v10zm2-8h6v6H9V9z"></path> 381</symbol> 382<symbol id="icon_close"> 383<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"></path> 384</symbol> 385<symbol id="icon_insertcomment"> 386<path d="M20 2H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h14l4 4V4c0-1.1-.9-2-2-2zm-2 12H6v-2h12v2zm0-3H6V9h12v2zm0-3H6V6h12v2z"></path> 387</symbol> 388<symbol id="icon_checkbox"> 389<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"></path> 390</symbol> 391<symbol id="icon_fileupload"> 392<path d="M9 16h6v-6h4l-7-7-7 7h4zm-4 2h14v2H5z"></path> 393</symbol> 394<symbol id="icon_filedownload"> 395<path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"></path> 396</symbol> 397</defs> 398</svg> 399 400<!-- used by invoke_with_user_inputs() to gather user inputs --> 401<div id="user_input_panel"></div> 402 403<!-- to show status messages --> 404<div id="message_panel"> 405<div id="message_panel_content" class="content"></div> 406</div> 407 408<!-- spreadsheet like editor for annotations --> 409<div id="annotation_editor_panel"> 410<div class="button_panel"> 411<span class="text_button" onclick="edit_region_metadata_in_annotation_editor()" id="button_edit_region_metadata" title="Manual annotations of regions">Region Annotations</span> 412<span class="text_button" onclick="edit_file_metadata_in_annotation_editor()" id="button_edit_file_metadata" title="Manual annotations of a file">File Annotations</span> 413 414<span class="button" style="float:right;margin-right:0.2rem;" onclick="annotation_editor_toggle_all_regions_editor()" title="Close this window of annotation editor">×</span> 415<span class="button" style="float:right;margin-right:0.2rem;" onclick="annotation_editor_increase_panel_height()" title="Increase the height of this panel">↑</span> 416<span class="button" style="float:right;margin-right:0.2rem;" onclick="annotation_editor_decrease_panel_height()" title="Decrease the height of this panel">↓</span> 417<span class="button" style="float:right;margin-right:0.2rem;" onclick="annotation_editor_increase_content_size()" title="Increase size of contents in annotation editor">+</span> 418<span class="button" style="float:right;margin-right:0.2rem;" onclick="annotation_editor_decrease_content_size()" title="Decrease size of contents in annotation editor">−</span> 419</div> 420<!-- here, a child div with id="annotation_editor" is added by javascript --> 421</div> 422 423<div class="top_panel" id="ui_top_panel"> 424<!-- menu bar --> 425<div class="menubar"> 426<ul> 427<li onclick="show_home_panel()" style="cursor:pointer;">Home</li> 428<li>Project 429<ul> 430<li onclick="project_open_select_project_file()" title="Load a VIA project (from a JSON file)">Load</li> 431<li onclick="project_save_with_confirm()" title="Save this VIA project (as a JSON file)">Save</li> 432<li onclick="settings_panel_toggle()" title="Show/edit project settings">Settings</li> 433<li class="submenu_divider"></li> 434<li onclick="sel_local_images()" title="Add images locally stored in this computer">Add local files</li> 435<li onclick="project_file_add_url_with_input()" title="Add images from a web URL (e.g. http://www.robots.ox.ac.uk/~vgg/software/via/images/swan.jpg)">Add files from URL</li> 436<li onclick="project_file_add_abs_path_with_input()" title="Add images using absolute path of file (e.g. /home/abhishek/image1.jpg)">Add file using absolute path</li> 437<li onclick="sel_local_data_file('files_url')" title="Add images from a list of web url or absolute path stored in a text file (one url or path per line)">Add url or path from text file</li> 438<li onclick="project_file_remove_with_confirm()" title="Remove selected file (i.e. file currently being shown)">Remove file</li> 439<li class="submenu_divider"></li> 440<li onclick="sel_local_data_file('attributes')" title="Import region and file attributes from a JSON file">Import region/file attributes</li> 441<li onclick="project_save_attributes()" title="Export region and file attributes to a JSON file">Export region/file attributes</li> 442</ul> 443</li> 444 445<li>Annotation 446<ul> 447<li onclick="download_all_region_data('csv')" title="Export annotations to a CSV file">Export Annotations (as csv)</li> 448<li onclick="download_all_region_data('json')" title="Export annotaitons to a JSON file">Export Annotations (as json)</li> 449<li onclick="download_all_region_data('coco', 'json')" title="Export annotaitons to COCO (http://cocodataset.org) format">Export Annotations (COCO format)</li> 450<li onclick="" class="submenu_divider"></li> 451<li onclick="sel_local_data_file('annotations')" title="Import annotations from a CSV file">Import Annotations (from csv)</li> 452<li onclick="sel_local_data_file('annotations')" title="Import annotations from a JSON file">Import Annotations (from json)</li> 453<li onclick="sel_local_data_file('annotations_coco')" title="Import annotations from a COCO (http://cocodataset.org) formatted JSON file">Import Annotations (COCO format)</li> 454 455<li class="submenu_divider"></li> 456<li onclick="show_annotation_data()" title="Show a preview of annotations (opens in a new browser windows)">Preview Annotations</li> 457<li onclick="download_as_image()" title="Download an image containing the annotations">Download as Image</li> 458</ul> 459</li> 460 461<li>View 462<ul> 463<li onclick="image_grid_toggle()" title="Toggle between single image view and image grid view">Toggle image grid view</li> 464<li onclick="leftsidebar_toggle()" title="Show or hide the sidebar shown in left hand side">Toggle left sidebar</li> 465<li onclick="toggle_img_fn_list_visibility()" title="Show or hide a panel to update annotations corresponding to file and region">Toggle image filename list</li> 466<li onclick="toggle_message_visibility()" title="Show or hide status messages that appears at the bottom of the page">Toggle status message visibility</li> 467<li class="submenu_divider"></li> 468<li onclick="toggle_attributes_editor()" title="Show or hide a panel to update file and region attributes">Toggle attributes editor</li> 469<li onclick="annotation_editor_toggle_all_regions_editor()" title="Show or hide a panel to update annotations corresponding to file and region">Toggle annotation editor (Space)</li> 470<li class="submenu_divider"></li> 471<li onclick="toggle_region_boundary_visibility()" title="Show or hide the region boundaries">Show/hide region boundaries (b)</li> 472<li onclick="toggle_region_id_visibility()" title="Show or hide the region id labels">Show/hide region labels (l)</li> 473<li onclick="toggle_region_info_visibility()" title="Show or hide the image coordinates">Show/hide region info.</li> 474</ul> 475</li> 476 477<li>Help 478<ul> 479<li onclick="set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_GETTING_STARTED)" title="Show a guide to get started with this application">Getting Started</li> 480<li title="Visit the project page for this application"><a href="http://www.robots.ox.ac.uk/~vgg/software/via/" target="_blank">VGG Project Page</a></li> 481<li onclick="" title="Report an issue to the developers of this application (requires an account at gitlab.com)"><a href="https://gitlab.com/vgg/via/issues" target="_blank">Report issues</a></li> 482<li class="submenu_divider"></li> 483<li><a target="_blank" href="https://gitlab.com/vgg/via/blob/master/Contributors.md" title="List of people who have contributed towards the development of VIA">Contributors</a></li> 484<li onclick="set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_LICENSE)" title="View license of this application">License</li> 485<li onclick="set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_ABOUT)" title="Show more details about this application">About VIA</li> 486</ul> 487</li> 488</ul> 489</div> <!-- end of menubar --> 490 491<!-- Shortcut toolbar --> 492<div class="toolbar"> 493<svg onclick="project_open_select_project_file()" viewbox="0 0 24 24"><use xlink:href="#icon_open"></use><title>Open Project</title></svg> 494<svg onclick="project_save_with_confirm()" viewbox="0 0 24 24"><use xlink:href="#icon_save"></use><title>Save Project</title></svg> 495<svg onclick="settings_panel_toggle()" viewbox="0 0 24 24"><use xlink:href="#icon_settings"></use><title>Update Project Settings</title></svg> 496<!-- 497<svg onclick="" viewbox="0 0 24 24"><use xlink:href="#icon_checkbox"></use><title>Locate Files</title></svg> 498--> 499 500<svg onclick="sel_local_data_file('annotations')" style="margin-left:1rem;" viewbox="0 0 24 24"><use xlink:href="#icon_fileupload"></use><title>Import Annotations from CSV</title></svg> 501<svg onclick="download_all_region_data('csv')" viewbox="0 0 24 24"><use xlink:href="#icon_filedownload"></use><title>Download Annotations as CSV</title></svg> 502 503<svg onclick="image_grid_toggle()" id="toolbar_image_grid_toggle" style="margin-left:1rem;" viewbox="0 0 24 24"><use xlink:href="#icon_gridon"></use><title>Switch to Image Grid View</title></svg> 504<svg onclick="annotation_editor_toggle_all_regions_editor()" viewbox="0 0 24 24"><use xlink:href="#icon_insertcomment"></use><title>Toggle Annotation Editor</title></svg> 505 506<svg onclick="move_to_prev_image()" style="margin-left:1rem;" viewbox="0 0 24 24"><use xlink:href="#icon_prev"></use><title>Previous</title></svg> 507<svg onclick="toggle_img_fn_list_visibility()" viewbox="0 0 24 24"><use xlink:href="#icon_list"></use><title>Toggle Filename List</title></svg> 508<svg onclick="move_to_next_image()" viewbox="0 0 24 24"><use xlink:href="#icon_next"></use><title>Next</title></svg> 509 510<svg onclick="zoom_in()" style="margin-left:1rem;" viewbox="0 0 24 24"><use xlink:href="#icon_zoomin"></use><title>Zoom In</title></svg> 511<svg onclick="zoom_out()" viewbox="0 0 24 24"><use xlink:href="#icon_zoomout"></use><title>Zoom Out</title></svg> 512 513<svg onclick="sel_all_regions()" viewbox="0 0 24 24" style="margin-left:1rem;"><use xlink:href="#icon_selectall"></use><title>Select All Regions</title></svg> 514<svg onclick="copy_sel_regions()" viewbox="0 0 24 24"><use xlink:href="#icon_copy"></use><title>Copy Regions</title></svg> 515<svg onclick="paste_sel_regions_in_current_image()" viewbox="0 0 24 24"><use xlink:href="#icon_paste"></use><title>Paste Regions</title></svg> 516<svg onclick="paste_to_multiple_images_with_confirm()" viewbox="0 0 24 24"><use xlink:href="#icon_pasten"></use><title>Paste Region in Multiple Images</title></svg> 517<svg onclick="del_sel_regions_with_confirm()" viewbox="0 0 24 24"><use xlink:href="#icon_pasteundo"></use><title>Undo Regions Pasted in Multiple Images</title></svg> 518<svg onclick="del_sel_regions()" viewbox="0 0 24 24"><use xlink:href="#icon_close"></use><title>Delete Region</title></svg> 519</div> 520<!-- end of shortcut toolbar --> 521<input type="file" id="invisible_file_input" name="files[]" style="display:none"> 522</div> <!-- endof #top_panel --> 523 524<!-- Middle Panel contains a left-sidebar and image display areas --> 525<div class="middle_panel"> 526<!-- this panel contains a button to shows the left side bar --> 527<div id="leftsidebar_collapse_panel"> 528<span class="text_button" onclick="leftsidebar_toggle()" title="Show left sidebar">▸</span> 529</div> 530 531<div id="leftsidebar"> 532<div class="leftsidebar_accordion_panel show" style="float:right; border:2px solid #f2f2f2;"> 533<span class="text_button" onclick="leftsidebar_decrease_width()" title="Reduce width of this toolbar panel">←</span> 534<span class="text_button" onclick="leftsidebar_increase_width()" title="Increase width of this toolbar panel">→</span> 535<span class="text_button" onclick="leftsidebar_toggle()" title="Show/hide this toolbar panel">◂</span> 536</div> 537 538<button class="leftsidebar_accordion active">Region Shape</button> 539<div class="leftsidebar_accordion_panel show"> 540<ul class="region_shape"> 541<li id="region_shape_rect" class="selected" onclick="select_region_shape('rect')" title="Rectangle (Shortcut key 1)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_rectangle"></use></svg></li> 542<li id="region_shape_circle" onclick="select_region_shape('circle')" title="Circle (Shortcut key 2)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_circle"></use></svg></li> 543<li id="region_shape_ellipse" onclick="select_region_shape('ellipse')" title="Ellipse (Shortcut key 3)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_ellipse"></use></svg></li> 544<li id="region_shape_polygon" onclick="select_region_shape('polygon')" title="Polygon (Shortcut key 4)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_polygon"></use></svg></li> 545<li id="region_shape_point" onclick="select_region_shape('point')" title="Point (Shortcut key 5)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_point"></use></svg></li> 546<li id="region_shape_polyline" onclick="select_region_shape('polyline')" title="Polyline (Shortcut key 6)"><svg height="32" viewbox="0 0 32 32"><use xlink:href="#shape_polyline"></use></svg></li> 547</ul> 548<div id="region_info" class="display_none"> </div> 549</div> 550 551<!-- Project --> 552<button class="leftsidebar_accordion active" id="project_panel_title">Project</button> 553<div class="leftsidebar_accordion_panel show" id="img_fn_list_panel"> 554<div id="project_info_panel"> 555<div class="row"> 556<span class="col"><label for="project_name">Name: </label></span> 557<span class="col"><input type="text" value="" onchange="project_on_name_update(this)" id="project_name" title="VIA project name"></span> 558</div> 559</div> 560<div id="project_tools_panel"> 561<div class="button_panel" style="margin:0.1rem 0;" > 562<select style="width:48%" id="filelist_preset_filters_list" onchange="img_fn_list_onpresetfilter_select()" title="Filter file list using predefined filters"> 563<option value="all">All files</option> 564<option value="files_without_region">Show files without regions</option> 565<option value="files_missing_region_annotations">Show files missing region annotations</option> 566<option value="files_missing_file_annotations">Show files missing file annotations</option> 567<option value="files_error_loading">Files that could not be loaded</option> 568<option value="regex">Regular Expression</option> 569<option value="files_region_attribute">Filter by Region Attribute</option> 570</select> 571<input style="width:50%" type="text" placeholder="regular expression" oninput="img_fn_list_onregex()" id="img_fn_list_regex" title="Filter using regular expression"> 572</div> 573</div> 574<div id="img_fn_list"></div> 575<p> 576<div class="button_panel"> 577<span class="button" onclick="sel_local_images()" title="Add new file from local disk">Add Files</span> 578<span class="button" onclick="project_file_add_url_with_input()" title="Add new file using URL">Add URL</span> 579<span class="button" onclick="project_file_remove_with_confirm()" title="Remove selected file (i.e. file currently being shown) from project">Remove</span> 580</div> 581</p> 582</div> 583 584<!-- Attributes --> 585<button class="leftsidebar_accordion" id="attributes_editor_panel_title">Attributes</button> 586<div class="leftsidebar_accordion_panel" id="attributes_editor_panel"> 587<div class="button_panel" style="padding:1rem 0;"> 588<span class="text_button" onclick="show_region_attributes_update_panel()" id="button_show_region_attributes" title="Show region attributes">Region Attributes</span> 589<span class="text_button" onclick="show_file_attributes_update_panel()" id="button_show_file_attributes" title="Show file attributes">File Attributes</span> 590</div> 591<div id="attributes_update_panel"> 592<div class="button_panel"> 593<input style="width:70%" type="text" placeholder="attribute name" id="user_input_attribute_id" value=""> 594<span id="button_add_new_attribute" class="button" onclick="add_new_attribute_from_user_input()" title="Add new attribute">+</span> 595<span id="button_del_attribute" class="button" onclick="delete_existing_attribute_with_confirm()" title="Delete existing attribute">−</span> 596</div> 597<div class="button_panel" style="margin:0.1rem 0;" > 598<select style="width:100%" id="attributes_name_list" onchange="update_current_attribute_id(this)" title="List of existing attributes"></select> 599</div> 600<div id="attribute_properties"></div> 601<div id="attribute_options"></div> 602<p style="text-align:center"> 603<span class="text_button" title="Show a spreadsheet like editor for all manual annotations" onclick="annotation_editor_toggle_all_regions_editor()">Toggle Annotation Editor</span> 604</p> 605</div> 606</div> 607 608<button class="leftsidebar_accordion">Keyboard Shortcuts</button> 609<div class="leftsidebar_accordion_panel"> 610<div style="display:block; text-align:center; padding:1rem;">Available only on image focus</div> 611<table> 612<tr> 613<td style="width:8em;"><span class="key">←</span> <span class="key">↑</span> <span class="key">→</span> <span class="key">↓</span></td> 614<td>Move selected region by 1 px (Shift to jump)</td> 615</tr> 616<tr> 617<td><span class="key">a</span></td> 618<td>Select all regions</td> 619</tr> 620 621<tr> 622<td><span class="key">c</span></td> 623<td>Copy selected regions</td> 624</tr> 625<tr> 626<td><span class="key">v</span></td> 627<td>Paste selected regions</td> 628</tr> 629<tr> 630<td><span class="key">d</span></td> 631<td>Delete selected regions</td> 632</tr> 633<tr> 634<td><span class="key">Ctrl</span> + Wheel</td> 635<td>Zoom in/out (mouse cursor is over image)</td> 636</tr> 637<tr> 638<td><span class="key">l</span></td> 639<td>Toggle region label</td> 640</tr> 641<tr> 642<td><span class="key">b</span></td> 643<td>Toggle region boundary</td> 644</tr> 645<tr> 646<td><span class="key">Enter</span></td> 647<td>Finish drawing polyshape</td> 648</tr> 649<tr> 650<td><span class="key">Backspace</span></td> 651<td>Delete last polyshape vertex</td> 652</tr> 653</table> 654 655<div style="display:block; text-align:center; padding:1rem;">Always Available</div> 656<table> 657<tr> 658<td style="width:8em;"><span class="key">←</span> <span class="key">→</span></td> 659<td>Move to next/previous image</td> 660</tr> 661<tr> 662<td><span class="key">+</span> <span class="key">-</span> <span class="key">=</span></td> 663<td>Zoom in/out/reset</td> 664</tr> 665<tr> 666<td><span class="key">↑</span></td> 667<td>Update region label</td> 668</tr> 669<tr> 670<td><span class="key">↓</span></td> 671<td>Update region colour</td> 672</tr> 673<tr> 674<td><span class="key">Spacebar</span></td> 675<td>Toggle annotation editor (Ctrl to toggle on image editor)</td> 676</tr> 677<tr> 678<td><span class="key">Home</span> / <span class="key">h</span></td> 679<td>Jump to first image</td> 680</tr> 681<tr> 682<td><span class="key">End</span> / <span class="key">e</span></td> 683<td>Jump to last image</td> 684</tr> 685<tr> 686<td><span class="key">PgUp</span> / <span class="key">u</span></td> 687<td>Jump several images</td> 688</tr> 689<tr> 690<td><span class="key">PgDown</span> / <span class="key">d</span></td> 691<td>Jump several images</td> 692</tr> 693 694<tr> 695<td><span class="key">Esc</span></td> 696<td>Cancel ongoing task</td> 697</tr> 698</table> 699</div> 700 701</div> <!-- end of leftsidebar --> 702 703<!-- Main display area: contains image canvas, ... --> 704<div id="display_area"> 705<div id="image_panel" class="display_area_content display_none"> 706<!-- buffer images using <img> element will be added here --> 707 708<!-- @todo: in future versions, this canvas will be replaced by a <svg> element --> 709<canvas id="region_canvas" width="1" height="1" tabindex="1">Sorry, your browser does not support HTML5 Canvas functionality which is required for this application.</canvas> 710<!-- here, a child div with id="annotation_editor" is added by javascript --> 711</div> 712<div id="image_grid_panel" class="display_area_content display_none"> 713 714<div id="image_grid_group_panel"> 715<span class="tool">Group by <select id="image_grid_toolbar_group_by_select" onchange="image_grid_toolbar_onchange_group_by_select(this)"></select></span> 716</div> 717 718<div id="image_grid_toolbar"> 719<span>Selected</span> 720<span id="image_grid_group_by_sel_img_count">0</span> 721<span>of</span> 722<span id="image_grid_group_by_img_count">0</span> 723<span>images in current group, show</span> 724 725<span> 726<select id="image_grid_show_image_policy" onchange="image_grid_onchange_show_image_policy(this)"> 727<option value="all">all images (paginated)</option> 728<option value="first_mid_last">only first, middle and last image</option> 729<option value="even_indexed">even indexed images (i.e. 0,2,4,...)</option> 730<option value="odd_indexed">odd indexed images (i.e. 1,3,5,...)</option> 731<option value="gap5">images 1, 5, 10, 15,...</option> 732<option value="gap25">images 1, 25, 50, 75, ...</option> 733<option value="gap50">images 1, 50, 100, 150, ...</option> 734</select> 735</span> 736 737<div id="image_grid_nav"></div> 738</div> 739 740<div id="image_grid_content"> 741<div id="image_grid_content_img"></div> 742<svg xmlns:xlink="http://www.w3.org/2000/svg" id="image_grid_content_rshape"></svg> 743</div> 744 745<div id="image_grid_info"> 746</div> 747</div> <!-- end of image grid panel --> 748 749<div id="settings_panel" class="display_area_content display_none"> 750<h2>Settings</h2> 751<div class="row"> 752<div class="variable"> 753<div class="name">Project Name</div> 754</div> 755 756<div class="value"> 757<input type="text" id="_via_settings.project.name"/> 758</div> 759</div> 760 761<div class="row"> 762<div class="variable"> 763<div class="name">Default Path</div> 764<div class="desc">If all images in your project are saved in a single folder, set the default path to the location of this folder. The VIA application will load images from this folder by default. Note: a default path of <code>"./"</code> indicates that the folder containing <code>via.html</code> application file also contains the images in this project. For example: <code>/datasets/VOC2012/JPEGImages/</code> or <code>C:\Documents\data\</code> <strong>(note the trailing <code>/</code> and <code>\</code></strong>)</div> 765</div> 766 767<div class="value"> 768<input type="text" id="_via_settings.core.default_filepath" placeholder="/datasets/pascal/voc2012/VOCdevkit/VOC2012/JPEGImages/"/> 769</div> 770</div> 771 772<div class="row"> 773<div class="variable"> 774<div class="name">Search Path List</div> 775<div class="desc">If you define multiple paths, all these folders will be searched to find images in this project. We do not recommend this approach as it is computationally expensive to search for images in multiple folders. <ol id="_via_settings.core.filepath"></ol></div> 776</div> 777 778<div class="value"> 779<input type="text" id="settings_input_new_filepath" placeholder="/datasets/pascal/voc2012/VOCdevkit/VOC2012/JPEGImages"/> 780</div> 781</div> 782 783<div class="row"> 784<div class="variable"> 785<div class="name">Region Label</div> 786<div class="desc">By default, each region in an image is labelled using the region-id. Here, you can select a more descriptive labelling of regions.</div> 787</div> 788 789<div class="value"> 790<select id="_via_settings.ui.image.region_label"></select> 791</div> 792</div> 793 794<div class="row"> 795<div class="variable"> 796<div class="name">Region Colour</div> 797<div class="desc">By default, each region is drawn using a single colour. Using this setting, you can assign a unique colour to regions grouped according to a region attribute.</div> 798</div> 799 800<div class="value"> 801<select id="_via_settings.ui.image.region_color"></select> 802</div> 803</div> 804 805<div class="row"> 806<div class="variable"> 807<div class="name">Region Label Font</div> 808<div class="desc">Font size and font family for showing region labels.</div> 809</div> 810 811<div class="value"> 812<input id="_via_settings.ui.image.region_label_font" placeholder="12px Arial"/> 813</div> 814</div> 815 816<div class="row"> 817<div class="variable"> 818<div class="name">Preload Buffer Size</div> 819<div class="desc">Images are preloaded in buffer to allow smoother navigation of next/prev images. A large buffer size may slow down the overall browser performance. To disable preloading, set buffer size to 0.</div> 820</div> 821<div class="value"> 822<input type="text" id="_via_settings.core.buffer_size" /> 823</div> 824</div> 825 826<div class="row"> 827<div class="variable"> 828<div class="name">On-image Annotation Editor</div> 829<div class="desc">When a single region is selected, the on-image annotation editor is gets activated which the user to update annotations of this region. By default, this on-image annotation editor is placed near the selected region.</div> 830</div> 831 832<div class="value"> 833<select id="_via_settings.ui.image.on_image_annotation_editor_placement"> 834<option value="NEAR_REGION">close to selected region</option> 835<option value="IMAGE_BOTTOM">at the bottom of image being annotated</option> 836<option value="DISABLE">DISABLE on-image annotation editor</option> 837</select> 838</div> 839</div> 840 841<div class="row" style="border:none;"> 842<button onclick="settings_save()" value="save_settings" style="margin-top:2rem">Save</button> 843<button onclick="settings_panel_toggle()" value="cancel_settings" style="margin-left:2rem;">Cancel</button> 844</div> 845</div> <!-- end of settings panel --> 846 847<div id="page_404" class="display_area_content display_none narrow_page_content"> 848<h2>File Not Found</h2> 849<p>Filename: <span style="font-family:Mono;" id="page_404_filename"></span></p> 850 851<p>We recommend that you update the default path in <span class="text_button" title="Show Project Settings" onclick="settings_panel_toggle()">project settings</span> to the folder which contains this image.</p> 852 853<p>A temporary fix is to use <span class="text_button" title="Load or Add Images" onclick="sel_local_images()">browser's file selector</span> to manually locate and add this file. We do not recommend this approach because it requires you to repeat this process every time your load this project in the VIA application.</p> 854</div> <!-- end of file not found panel --> 855 856<div id="page_start_info" class="display_area_content display_none narrow_page_content"> 857<ul> 858<li>To start annotation, <span class="text_button" title="Load or Add Images" onclick="sel_local_images()">select images</span> (or, add images from <span class="text_button" title="Add images from a web URL (e.g. http://www.robots.ox.ac.uk/~vgg/software/via/images/swan.jpg)" onclick="project_file_add_url_with_input()">URL</span> or <span class="text_button" title="Add images using absolute path of file (e.g. /home/abhishek/image1.jpg)" onclick="project_file_add_abs_path_with_input()">absolute path</span>) and draw regions</li> 859<li>Use <span class="text_button" title="Toggle attributes editor panel" onclick="toggle_attributes_editor()">attribute editor</span> to define attributes (e.g. name) and <span class="text_button" title="Toggle annotations editor panel" onclick="annotation_editor_toggle_all_regions_editor()">annotation editor</span> to describe each region (e.g. cat) using these attributes.</li> 860<li>Remember to <span class="text_button" onclick="project_save_with_confirm()">save</span> your project before closing this application so that you can <span class="text_button" onclick="project_open_select_project_file()">load</span> it later to continue annotation.</li> 861<li>For help, see the <span class="text_button" onclick="set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_GETTING_STARTED)">Getting Started</span> page and pre-loaded demo: <a href="http://www.robots.ox.ac.uk/~vgg/software/via/via_demo.html">image annotation</a> and <a href="http://www.robots.ox.ac.uk/~vgg/software/via/via_face_demo.html">face annotation</a>.</li> 862</ul> 863 864</div> 865 866<div id="page_getting_started" class="display_area_content display_none narrow_page_content"> 867<p>A more detailed user guide (with screenshots and descriptions) is <a href="http://www.robots.ox.ac.uk/~vgg/software/via/docs/user_guide.html">available here</a>.</p> 868<ol> 869<li><strong>Load Images</strong>: The first step is to load all the images that you wish to annotate. There are multiple ways to add images to a VIA project. Choose the method that suits your use case. 870<ul> 871<li>Method 1: Selecting local files using browser's file selector 872<ol> 873<li>Click <span class="text_button" title="Load or Add Images" onclick="sel_local_images()"><code>Project → Add local files</code></span></li> 874<li>Select desired images and click <code>Open</code></li> 875</ol> 876</li> 877<li>Method 2: Adding files from URL or absolute path 878<ol> 879<li>Click <span class="text_button" title="Add images from a web URL (e.g. http://www.robots.ox.ac.uk/~vgg/software/via/images/swan.jpg)" onclick="project_file_add_url_with_input()"><code>Project → Add files from URL</code></span></li> 880<li>Enter URL and click <code>OK</code></li> 881</ol> 882</li> 883<li>Method 3: Adding files from list of url or absolute path stored in text file 884<ol> 885<li>Create a text file containing URL and absolute path (one per line)</li> 886<li>Click <span class="text_button" title="Add images from a list of web url or absolute path stored in a text file (one url or path per line)" onclick="sel_local_data_file('files_url')"><code>Project → Add url or path from text file</code></span></li> 887<li>Select the text file and click <code>Open</code></li> 888</ol> 889</li> 890</ul> 891</li> 892<li><strong>Draw Regions</strong>: Select a region shape (<span class="text_button" onclick="select_region_shape('rect')">rectangle</span>, <span class="text_button" onclick="select_region_shape('circle')">circle</span>, <span class="text_button" onclick="select_region_shape('ellipse')">ellipse</span>, <span class="text_button" onclick="select_region_shape('polygon')">polygon</span>, <span class="text_button" onclick="select_region_shape('point')">point</span>, <span class="text_button" onclick="select_region_shape('polyline')">polyline</span>) from the left sidebar and draw regions as follows: 893 894<ul> 895<li>Rectangle, Circle and Ellipse 896<ul> 897<li>Press left mouse button, drag mouse cursor and release mouse button.</li> 898<li>To define a point inside an existing region, click inside the region to select it (if not already selected), now press left mouse button, drag and release to draw region inside existing region.</li> 899<li>To select, click inside the region. If the click point contains multiple regions, then clicking multiple times at that location shuffles selection through those regions.</li> 900</ul> 901</li> 902</ul> 903 904<ul> 905<li>Point 906<ul> 907<li>Click to define points.</li> 908<li>To draw a region inside existing region, click inside the region to select it (if not already selected), now click again to define the point.</li> 909<li>To select, click on (or near) the existing point.</li> 910</ul> 911</li> 912</ul> 913 914<ul> 915<li>Polygon and Polyline 916<ul> 917<li>Click to define vertices.</li> 918<li>Press <strong>[Enter]</strong> to finish drawing the region or press [Esc] to cancel.</li> 919<li>If the first vertex needs to be defined inside an existing region, click inside the region to select it (if not already selected), now click again to define the vertex.</li> 920<li>To select, click inside the region. If the click point contains multiple regions, then clicking multiple times at that location shuffles selection through those regions.</li> 921</ul> 922</li> 923</ul> 924</li> 925 926<li><strong>Create Annotations</strong>: For a more detailed description of this step, see <a href="http://www.robots.ox.ac.uk/~vgg/software/via/docs/creating_annotations.html">Creating Annotations : VIA User Guide</a>. Click the <span class="text_button" onclick="annotation_editor_toggle_all_regions_editor()"><code>View → Toggle attributes editor</code></span> to show attributes editor panel in left sidebar and add the desired file or region attributes (e.g. name). Now click <span class="text_button" onclick="annotation_editor_toggle_all_regions_editor()"><code>View → Toggle annotations editor</code></span> to show the annotation editor panel in the bottom side. Update the annotations for each region.</li> 927<li><strong>Export Annotations</strong>: To export the annotations in json or csv format, click <span class="text_button" onclick="download_all_region_data('csv')"><code>Annotation → Export annotations</code></span> in top menubar.</li> 928<li><strong>Save Project</strong>: To save the project, click <span class="text_button" onclick="project_save_with_confirm()"><code>Project → Save</code></span> in top menubar.</li> 929</ol> 930</div> 931 932<div id="page_load_ongoing" class="display_area_content narrow_page_content"> 933<div style="text-align:center"> 934<a href="http://www.robots.ox.ac.uk/~vgg/software/via/"> 935<svg height="160" viewbox="0 0 400 160" style="background-color:#212121;"> 936<use xlink:href="#via_logo"></use> 937</svg> 938</a> 939<div style="margin-top:4rem">Loading ...</div> 940</div> 941</div> 942 943<div id="page_about" class="display_area_content display_none" style="width:40rem !important"> 944<div style="text-align:center"> 945<a href="http://www.robots.ox.ac.uk/~vgg/software/via/"> 946<svg height="160" viewbox="0 0 400 160" style="background-color:#212121;"> 947<use xlink:href="#via_logo"></use> 948</svg> 949</a> 950</div> 951 952<p style="font-family:mono; font-size:0.8em;text-align:center;"><a href="https://gitlab.com/vgg/via/blob/master/CHANGELOG">Version 2.0.12</a></p> 953<p>VGG Image Annotator (VIA) is an image annotation tool that can be used to define regions in an image and create textual descriptions of those regions. VIA is an <a href="https://gitlab.com/vgg/via/">open source project</a> developed at the <a href="http://www.robots.ox.ac.uk/~vgg/">Visual Geometry Group</a> and released under the BSD-2 clause <a href="https://gitlab.com/vgg/via/blob/master/LICENSE">license</a>.</p> 954<p>Here is a list of some salient features of VIA: 955<ul> 956<li>based solely on HTML, CSS and Javascript (no external javascript libraries)</li> 957<li>can be used off-line (full application in a single html file of size < 400KB)</li> 958<li>requires nothing more than a modern web browser (tested on Firefox, Chrome and Safari)</li> 959<li>supported region shapes: rectangle, circle, ellipse, polygon, point and polyline</li> 960<li>import/export of region data in csv and json file format</li> 961</ul> 962</p> 963<p>For more details, visit <a href="http://www.robots.ox.ac.uk/~vgg/software/via/">http://www.robots.ox.ac.uk/~vgg/software/via/</a>.</p> 964<p> </p> 965<p>Copyright © 2016-2021, <a href="mailto:adutta-removeme@robots.ox.ac.uk">Abhishek Dutta</a>,Visual Geometry Group, Oxford University and <a target="_blank" href="https://gitlab.com/vgg/via/blob/master/Contributors.md">VIA Contributors</a>.</p> 966</div> <!-- end of page_about --> 967 968<div id="page_license" class="display_area_content display_none narrow_page_content"> 969<pre> 970Copyright (c) 2016-2022, Abhishek Dutta, Visual Geometry Group, Oxford University and VIA Contributors. 971All rights reserved. 972 973Redistribution and use in source and binary forms, with or without 974modification, are permitted provided that the following conditions are met: 975 976Redistributions of source code must retain the above copyright notice, this 977list of conditions and the following disclaimer. 978Redistributions in binary form must reproduce the above copyright notice, 979this list of conditions and the following disclaimer in the documentation 980and/or other materials provided with the distribution. 981THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 982AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 983IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 984ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 985LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 986CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 987SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 988INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 989CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 990ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 991POSSIBILITY OF SUCH DAMAGE. 992</pre> 993</div> 994</div> <!-- end of display_area --> 995</div> <!-- end of middle_panel --> 996 997<!-- this vertical spacer is needed to allow scrollbar to show 998items like Keyboard Shortcut hidden under the attributes panel --> 999<div style="width: 100%;" id="vertical_space"></div> 1000 1001<!-- START: Contents of file: src/demo/_via_basic_demo.js--> 1002<script> 1003/* 1004VGG Image Annotator (via) 1005www.robots.ox.ac.uk/~vgg/software/via/ 1006 1007Copyright (c) 2016-2018, Abhishek Dutta. 1008All rights reserved. 1009 1010Redistribution and use in source and binary forms, with or without 1011modification, are permitted provided that the following conditions are met: 1012 1013Redistributions of source code must retain the above copyright notice, this 1014list of conditions and the following disclaimer. 1015Redistributions in binary form must reproduce the above copyright notice, 1016this list of conditions and the following disclaimer in the documentation 1017and/or other materials provided with the distribution. 1018THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1019AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1020IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1021ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1022LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1023CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1024SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1025INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1026CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1027ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1028POSSIBILITY OF SUCH DAMAGE. 1029*/ 1030 1031function _via_load_submodules() { 1032_via_basic_demo_load_img(); 1033//_via_basic_demo_draw_default_regions(); 1034_via_basic_demo_define_attributes(); 1035_via_basic_demo_define_annotations(); 1036 1037toggle_attributes_editor(); 1038update_attributes_update_panel(); 1039 1040annotation_editor_show(); 1041} 1042 1043function _via_basic_demo_load_img() { 1044// add files 1045var i, n; 1046var file_count = 0; 1047n = _via_basic_demo_img.length; 1048for ( i = 0; i < n; ++i ) { 1049project_file_add_base64( _via_basic_demo_img_filename[i], _via_basic_demo_img[i] ); 1050file_count += 1; 1051} 1052 1053_via_show_img(0); 1054update_img_fn_list(); 1055} 1056 1057function _via_basic_demo_draw_default_regions() { 1058var csv_annotations = 'filename,file_size,file_attributes,region_count,region_id,region_shape_attributes,region_attributes\nadutta_swan.jpg,-1,"{}",1,0,"{""name"":""polygon"",""all_points_x"":[116,94,176,343,383,385,369,406,398,364,310,297,304,244,158],""all_points_y"":[157,195,264,273,261,234,222,216,155,124,135,170,188,170,175]}","{}"\nwikimedia_death_of_socrates.jpg,-1,"{}",3,0,"{""name"":""rect"",""x"":174,""y"":139,""width"":108,""height"":227}","{}"\nwikimedia_death_of_socrates.jpg,-1,"{}",3,1,"{""name"":""rect"",""x"":347,""y"":114,""width"":91,""height"":209}","{}"\nwikimedia_death_of_socrates.jpg,-1,"{}",3,2,"{""name"":""ellipse"",""cx"":316,""cy"":180,""rx"":17,""ry"":12}","{}"'; 1059 1060import_annotations_from_csv(csv_annotations); 1061} 1062 1063function _via_basic_demo_define_attributes() { 1064var attributes_json = '{"region":{"name":{"type":"text","description":"Name of the object","default_value":"not_defined"},"type":{"type":"dropdown","description":"Category of object","options":{"bird":"Bird","human":"Human","cup":"Cup (object)","unknown":"Unknown (object)"},"default_options":{"unknown":true}},"image_quality":{"type":"checkbox","description":"Quality of image region","options":{"blur":"Blurred region","good_illumination":"Good Illumination","frontal":"Object in Frontal View"},"default_options":{"good":true,"frontal":true,"good_illumination":true}}},"file":{"caption":{"type":"text","description":"","default_value":""},"public_domain":{"type":"radio","description":"","options":{"yes":"Yes","no":"No"},"default_options":{"no":true}},"image_url":{"type":"text","description":"","default_value":""}}}'; 1065 1066project_import_attributes_from_json(attributes_json); 1067} 1068 1069function _via_basic_demo_define_annotations() { 1070var annotations_json = '{"adutta_swan.jpg-1":{"filename":"adutta_swan.jpg","size":-1,"regions":[{"shape_attributes":{"name":"polygon","all_points_x":[116,94,176,343,383,385,369,406,398,364,310,297,304,244,158],"all_points_y":[157,195,264,273,261,234,222,216,155,124,135,170,188,170,175]},"region_attributes":{"name":"Swan","type":"bird","image_quality":{"good_illumination":true}}}],"file_attributes":{"caption":"Swan in lake Geneve","public_domain":"no","image_url":"http://www.robots.ox.ac.uk/~vgg/software/via/images/swan.jpg"}},"wikimedia_death_of_socrates.jpg-1":{"filename":"wikimedia_death_of_socrates.jpg","size":-1,"regions":[{"shape_attributes":{"name":"rect","x":174,"y":139,"width":108,"height":227},"region_attributes":{"name":"Plato","type":"human","image_quality":{"good_illumination":true}}},{"shape_attributes":{"name":"rect","x":347,"y":114,"width":91,"height":209},"region_attributes":{"name":"Socrates","type":"human","image_quality":{"frontal":true,"good_illumination":true}}},{"shape_attributes":{"name":"ellipse","cx":316,"cy":180,"rx":17,"ry":12},"region_attributes":{"name":"Hemlock","type":"cup"}}],"file_attributes":{"caption":"The Death of Socrates by David","public_domain":"yes","image_url":"https://en.wikipedia.org/wiki/The_Death_of_Socrates#/media/File:David_-_The_Death_of_Socrates.jpg"}}}'; 1071 1072import_annotations_from_json(annotations_json); 1073} 1074 1075var _via_basic_demo_img = []; 1076var _via_basic_demo_img_filename = ['adutta_swan.jpg', 'wikimedia_death_of_socrates.jpg']; 1077 1078// adutta_swan.jpg 1079_via_basic_demo_img.push('data:image/jpeg;base64,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H//Z/+EJf2h0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSfvu78nIGlkPSdXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQnPz4KPHg6eG1wbWV0YSB4bWxuczp4PSdhZG9iZTpuczptZXRhLyc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyc+CgogPHJkZjpEZXNjcmlwdGlvbiB4bWxuczpleGlmPSdodHRwOi8vbnMuYWRvYmUuY29tL2V4aWYvMS4wLyc+CiAgPGV4aWY6T3JpZW50YXRpb24+VG9wLWxlZnQ8L2V4aWY6T3JpZW50YXRpb24+CiAgPGV4aWY6WFJlc29sdXRpb24+NzI8L2V4aWY6WFJlc29sdXRpb24+CiAgPGV4aWY6WVJlc29sdXRpb24+NzI8L2V4aWY6WVJlc29sdXRpb24+CiAgPGV4aWY6UmVzb2x1dGlvblVuaXQ+SW5jaDwvZXhpZjpSZXNvbHV0aW9uVW5pdD4KICA8ZXhpZjpTb2Z0d2FyZT5QaWNhc2E8L2V4aWY6U29mdHdhcmU+CiAgPGV4aWY6Q29tcHJlc3Npb24+SlBFRyBjb21wcmVzc2lvbjwvZXhpZjpDb21wcmVzc2lvbj4KICA8ZXhpZjpYUmVzb2x1dGlvbj43MjwvZXhpZjpYUmVzb2x1dGlvbj4KICA8ZXhpZjpZUmVzb2x1dGlvbj43MjwvZXhpZjpZUmVzb2x1dGlvbj4KICA8ZXhpZjpSZXNvbHV0aW9uVW5pdD5JbmNoPC9leGlmOlJlc29sdXRpb25Vbml0PgogIDxleGlmOkZsYXNoUGl4VmVyc2lvbj5GbGFzaFBpeCBWZXJzaW9uIDEuMDwvZXhpZjpGbGFzaFBpeFZlcnNpb24+CiAgPGV4aWY6SW50ZXJvcGVyYWJpbGl0eUluZGV4PlI5ODwvZXhpZjpJbnRlcm9wZXJhYmlsaXR5SW5kZXg+CiAgPGV4aWY6SW50ZXJvcGVyYWJpbGl0eVZlcnNpb24+MDEwMDwvZXhpZjpJbnRlcm9wZXJhYmlsaXR5VmVyc2lvbj4KICA8ZXhpZjpPcmllbnRhdGlvbj5Ub3AtbGVmdDwvZXhpZjpPcmllbnRhdGlvbj4KICA8ZXhpZjpYUmVzb2x1dGlvbj43MjwvZXhpZjpYUmVzb2x1dGlvbj4KICA8ZXhpZjpZUmVzb2x1dGlvbj43MjwvZXhpZjpZUmVzb2x1dGlvbj4KICA8ZXhpZjpSZXNvbHV0aW9uVW5pdD5JbmNoPC9leGlmOlJlc29sdXRpb25Vbml0PgogIDxleGlmOlNvZnR3YXJlPkdJTVAgMi44LjE2PC9leGlmOlNvZnR3YXJlPgogIDxleGlmOkNvbXByZXNzaW9uPkpQRUcgY29tcHJlc3Npb248L2V4aWY6Q29tcHJlc3Npb24+CiAgPGV4aWY6WFJlc29sdXRpb24+NzI8L2V4aWY6WFJlc29sdXRpb24+CiAgPGV4aWY6WVJlc29sdXRpb24+NzI8L2V4aWY6WVJlc29sdXRpb24+CiAgPGV4aWY6UmVzb2x1dGlvblVuaXQ+SW5jaDwvZXhpZjpSZXNvbHV0aW9uVW5pdD4KICA8ZXhpZjpGbGFzaFBpeFZlcnNpb24+Rmxhc2hQaXggVmVyc2lvbiAxLjA8L2V4aWY6Rmxhc2hQaXhWZXJzaW9uPgogIDxleGlmOkludGVyb3BlcmFiaWxpdHlJbmRleD5SOTg8L2V4aWY6SW50ZXJvcGVyYWJpbGl0eUluZGV4PgogIDxleGlmOkludGVyb3BlcmFiaWxpdHlWZXJzaW9uPjAxMDA8L2V4aWY6SW50ZXJvcGVyYWJpbGl0eVZlcnNpb24+CiAgPGV4aWY6T3JpZW50YXRpb24+VG9wLWxlZnQ8L2V4aWY6T3JpZW50YXRpb24+CiAgPGV4aWY6WFJlc29sdXRpb24+NzI8L2V4aWY6WFJlc29sdXRpb24+CiAgPGV4aWY6WVJlc29sdXRpb24+NzI8L2V4aWY6WVJlc29sdXRpb24+CiAgPGV4aWY6UmVzb2x1dGlvblVuaXQ+SW5jaDwvZXhpZjpSZXNvbHV0aW9uVW5pdD4KICA8ZXhpZjpTb2Z0d2FyZT5QaWNhc2E8L2V4aWY6U29mdHdhcmU+CiAgPGV4aWY6Q29tcHJlc3Npb24+SlBFRyBjb21wcmVzc2lvbjwvZXhpZjpDb21wcmVzc2lvbj4KICA8ZXhpZjpYUmVzb2x1dGlvbj43MjwvZXhpZjpYUmVzb2x1dGlvbj4KICA8ZXhpZjpZUmVzb2x1dGlvbj43MjwvZXhpZjpZUmVzb2x1dGlvbj4KICA8ZXhpZjpSZXNvbHV0aW9uVW5pdD5JbmNoPC9leGlmOlJlc29sdXRpb25Vbml0PgogIDxleGlmOkV4aWZWZXJzaW9uPkV4aWYgVmVyc2lvbiAyLjI8L2V4aWY6RXhpZlZlcnNpb24+CiAgPGV4aWY6Rmxhc2hQaXhWZXJzaW9uPkZsYXNoUGl4IFZlcnNpb24gMS4wPC9leGlmOkZsYXNoUGl4VmVyc2lvbj4KICA8ZXhpZjpDb2xvclNwYWNlPnNSR0I8L2V4aWY6Q29sb3JTcGFjZT4KICA8ZXhpZjpQaXhlbFhEaW1lbnNpb24+MTI5NjwvZXhpZjpQaXhlbFhEaW1lbnNpb24+CiAgPGV4aWY6UGl4ZWxZRGltZW5zaW9uPjg2NDwvZXhpZjpQaXhlbFlEaW1lbnNpb24+CiAgPGV4aWY6SW1hZ2VVbmlxdWVJRD44ZWYyN2RiM2M3YjY4ZTM5MDAwMDAwMDAwMDAwMDAwMDwvZXhpZjpJbWFnZVVuaXF1ZUlEPgogIDxleGlmOkludGVyb3BlcmFiaWxpdHlJbmRleD5SOTg8L2V4aWY6SW50ZXJvcGVyYWJpbGl0eUluZGV4PgogIDxleGlmOkludGVyb3BlcmFiaWxpdHlWZXJzaW9uPjAxMDA8L2V4aWY6SW50ZXJvcGVyYWJpbGl0eVZlcnNpb24+CiA8L3JkZjpEZXNjcmlwdGlvbj4KCjwvcmRmOlJERj4KPC94OnhtcG1ldGE+Cjw/eHBhY2tldCBlbmQ9J3InPz4K/9sAQwADAgILCggICgoKCAgICAgHBwgICAgICAcHBwcHBwcHBwcICAgIBwcHBwcHBwcKBwcICAkJCQcHDQ0KCA0HCAkI/9sAQwEDBAQGBQYIBgYKDQ0IDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0NDQ0N/8IAEQgBkAJYAwERAAIRAQMRAf/EABwAAAIDAQEBAQAAAAAAAAAAAAMEAQIFAAYHCP/EABsBAAMBAQEBAQAAAAAAAAAAAAABAgMEBQYH/9oADAMBAAIQAxAAAAGPZ8avPVWW1zXYKWzaIAYpWW+xsFgmpAiB6KL6TRMLEoqkMTBtWcxFBllGSpkZxDoRhuMYuay1QWYMdJd4ZBEtMUUC6BUVzojR7TbWdnS9HNWA6CTWehdzzYJpgkdgpbYNOUs9IkOKtJUqks1SdF6WtUookCWnbljOlGTc6M0e5pnSdqGqIAnnIXzorTukkRzDoWmxhdzVqVV6lpsgKApJM1bSa5ujVZu6BIdp6FTCEZuiHRW0mWL5sLBMy0zoLoiNS2nIKWKHVB6V2gj0bTFJSaHJoarswaF5a0VEOto4jWtHbI0sIUTpNS3dJlKuiDDBNWo0bily1LumGQFoCLIhJYp6wghjuM5KoZ0MjbrLAtJVptgU751egbQZEot1qtqXJGBCaGELJ1hluRqk7QJdKS+diRpBZA0j6hWhtRQ2LgFDqqrSmCZdAEgJVZXrNsuhltBaTYZolKsUhm17Tbds3RthzFyNNXOqJlE1pNmgTSkutFmLwLy37TLlWKDQZmqDKKJ0QtSs3mJIplVMNEaCmKGUSrMyKljLU2XRepAqcqdAfS5BzSU2AgtSzk0srgfOaNnoJatm+kb0nk04teD1uvPnwyMapNaBUIy14c2igNMgN3M5XVBaS+drAULbZpIO28KGxTXSWBZjYraKqE0Dkohkd5YR5cgaCCIOghDWoOiyd7G9ocFA1EK5VYDUj3LE1kp5UPkEFVslJ6psyUVQOmknaAzCZ3yZqmNIFR6hQyMCkdC6aKdmcgEuM6dpFcwC4DaSirMZBqkUnapLDyx5UVyG05ly1nSCoox+nAXzcpTZZotyWnCASUGFlUXpczk1AHLZqSMgHE7szYKpltVRUGaSQxySNdNZM4j0mmhCAqVihZ1FNuo6j6Is0RQVFQAJp2kunek40CGmlQIkWm4FWlVBdCmdZ0s4nKTgipLKsoYxOU026pXobpFQplQ0M3J6EWwy5pyJoCUqNCQIabE4u6H6k4Jy1UxSQh201rI0Cmj0qTRILUlAswoL5uU3dZK5WTRHCDs9Dkr6QAYw5pgbQXpZ8isskjFIyoGbWpWaAyMqhkBKHQAJYd7Gg1NM60lpdJchnK1opFBmWzpdMblnZN2pSGM4VqVlRkDaPRdpVUomYVwvRSQwEoXEzNMJ85Vazs2zQ3Ypmwg9aAhGBdUyyQWHQftzGQbuLsuNWWkwYMUoRdCudJImKfuW2rAO0vDzA1oOpgofqbtLS4GGGKBi0zalMDFJdAMM6AuchWIGLL2gy7J6AXqC2JpjQIZGRUxLZa06SqaoEFkZXmzTznQ0RWK5ujY0CVGJ0qS80DFyPZ0imixYeyoUyq2kDpjlwhdhkM0r2pQaG7omJqbhNNgKUqsdEKRQYoa8OE6uV5bUJykRihQKHaLWgyK0wj1qjQtJxWJFiRWxsScVnxQE9TWNLWSNCFSadihtjJVky4u9Ho9cwIQlpJ2Tpalq0i+dEoGjR0k0UlnSMvTpEqdbfBlMacoPU21BSxQxIJBfRWQrna4EaaYsi7U0qy182Js7R2hy4obaPC4dGiMzE14aircuXNoXbQhpqrC2LDCyhpmjtRq0mELWls2KkBOmd5yKywRWhrDGiBm8rK3qXXNwExpOjRRaqM1NVUZq6bEhZawM0n+rAObvIZqs1FrrRhWhpy1RiA9BUUiqtc1RlZagn2aWiMIaIGtIomeVdUClYR2mE6poSAhl1Tth6ScvKVJJxFv1OneaVg00srQT0bgcXSiHNQKNOAw04tZDOk62mbLRGQNOKHnQ4HbQxoDEjYl3movO1J7XIzKiUlhzpYD6SwyyfSgy72jWQgKFJqQgTFp9g83ixS0OFJ29DRMNLJwhilRA0ySnGyaKgAQsheKlh9FpVNU8xNNMSaAnGQ3lxVU2LmRQwrLofpbGsxDUYhNZ+biaDSeG8LgJIVqBqUTlXS4AkjvTzZ2dZ2V2Zrbw7pOblSkU4xupZ0XUl5qqRBMUQ0UastKQLbVSwg7KIXi04OpWZyK09OQcVVrnIhhhjRs0q2s6aTHWXOYrSSqrtDA1N+54LycJRMbfNXEvLIBAbpP0hDGhKaUmjiapONOtNtDtcqJLVEDOXNFDOZnZiypnRMUDk0lIaEZdopMKsuIzCJqirQwwwpYhm5b02mGqsUxq7TMNSKLoASFLe1TrQU8Ln0NpLemc5tcOtnpcxVOoKUJyxyy5vmaOi4RGupAbsgIChiQ+x+5boDSBLXxsE0WWtcojfyo9TXSPSdGKQzoMKqKpjEfQHIlNUQVMjLVEzUXN2hyzNyPIBfN1VNiapACgFo0ySNoZUvL6KYZW0njVgaudPRKws+as0zU00TLQ01imIVGJjhitO8lUxgRAqSo5cvM0AI1cFM6DLV0HaXOcqLHho4kahxoVTAgS7AS5oy8typPQpIy1FBWtTSToSyuNJA0vLI0pNK5UHRbOi0GiDWaRl52dxm+AUMgtFi8uGtbeAxQsrCmNliSiataNTAYUXnBt1DiaqLDi03cq56ZjGaXNdLrYvKTTsnw1UxZNgFtUgM7NYm2imC2FKq0Kk4vpfVzrUZUnFOVJ7Scteas0+JbN42VrU+qTNWT4Bg4g1pajKytTOqy4ZzNPWGQtQVAoYs6Axfn0z8r19YbEpDpaJojJaNv2Zp6zLVpVl1l8+15Es7m5ZDqE2hZt7eSaCUJS6vJYNWCZMsM8qU5BalLCMbF2iWbZgEmlDyhmylrWdjSGhpy8ySiDsqOgGYNA0FaoNaXSRqloUk6XVTjRBSIrpFPJijSBigyaW0P0iUmEztY2FjzrYpAAGVNt/Y56tDn31cr1MddHG/A9XL8D6/OrrmzohZUxZp1OfaSTFogy8vO6jYkZJYputDGonnCUYFMVVYWik21dpq5m0/EpBIDAomdE1RSBWHkTS8VLUhAOUnLl6lTOgNO6SlNZE0yyktBPRqXNJz1XS4CsUtLWipasw9RtoVi4a0GfV+bt9Dwdydx1TvY7en5NNe8fg/q+f896+TIzfNiTyJcyX1mN0/UFsYgthc8+qTB2i6TYO0VKjmLp5ZS0VdO1JgQmfQNeYNC6paCkg21UVHMl01BHpP6S2KE0pYJfDE3RF6HdJWhyBBKzRbTbRGa1LMh5cMjCMKxslSaJIy2NX+iPE9kvJ0fPdYy+7z/pHH26nNr7FZeW6sPzT28XdmAs2OKac02hW1lukQYVaKVLVkFlwmrLtcuaz1SADA4K4JUY06WzdrNZYksmSrCMDDypfBzDBLVExw6JDddSbaZQsi1B6JaYQFVVl081AobVrPkMGtojCEykttJ8EWlIr1EdH37wvY2sNPzn38fiPX8j33B6H1rz/QXzfu1j+Sve8rMhTS0LTsCsPE0nG3G5H5JlqWVphEbC2qm+sZVETS8sEtpF2mbmnQpTdlMVm5SBDRil5LN6+ubDBBVq80FCqYmfUMujyOmGSkumlLEmmMBQ0aFy3cBVP6xvWVgSTpJZCwDHMjUi002hvbHay6P0T4ft+gyj4v3c/wAb9Tzc3HX7Fxej8Kd/q7Bfmnu8yJegIWdURepU6Y60+y7QElm8y23pm+qbhKM12goXHUEgqOgZuwWh5TXnE0yUN3JnK0tCWJVotbO0nqU5LD5H2jm7vqnL0fKt8Pi+nPnXm7pMgeb9Db36bA9xvQ0XtcdXc7Mnk3PmXCYvOk/PVPk5b5DNJLCy5a/rDyvX9LnHl9c/xp6/AyR6nDq1flf0PzH0fxSnT5Cm6tzs82TfFjSWpLy2VMaI0teTzOrWdaItFqsmPjozIjojhfRGENmfost1VV7F85bUpUTkHdE4EJJy8uLVkdpaMuKmpf2zn7fr/N0Vc4XRl4XpwnafY5bMSyp9DyejJYnZz1axqjDRbkvkWClHlnHyLTn+UKXajT0X6D8X2fectuaYfkj2uDG1xUx1+m/C/qmP7ny3gve+TAJlDUgQEpzJ1LDKkqGik2GfvPS1RkYxDLNU1z1dYVBOaUoMA2nMrRtOa5hmQlBG25kUWGBaWArQuNGS0BLfNUT+1Y9n1/n6Mylh6Dzmdc70WpDYOpJDvNXh3pFQfLQgWTPk7zXUvnPTz/At+XIk+q+d6P3LzuvV0w/N/Zz/ABTfB7N/VPK+42Ojh+S+r8itcswWAzSUsEU7BOgmnbCnkLaydiWiDFPwL6ySWnpOnJk0CYRowb3NrZJf1OVEcjuFUlpoUOEnNEfVESdkvm0m6S4Ta0X6N5fQ9rjpkoyRB1k28OzXCKmznVGRSaQaKPDlkIsEhZBUeS9Dk+I9nJ5vzen9KeP6/pDPzu+P5D9XhsRpx0JJpVzjbdgXaHnUQToiAvSurdeejjdsqhLNpH59cvfNPY0ZWXtmq7aH0zyehNOxTUVjelxw7mhpy5UlakAoAmoNZI/PdYpaHAPUqUnXX2fLp+u47LbLMuUJennRUHBsYKRENS2QKFwsggWFyJCA+eerx+c7eT1PzXuev5ae3x+PdeP5u351xcDDCyGakQJfTSwzpFAQWzYkWTZydqHsng7BZKMV0SOg2LWqW8qy7G7gCI68j1JmDkUmhgZjFoQVYGBZNyWxKqBW7iiaMHvp2+rm+tnT2dJw0qH6k6GR2l3kuBxsJXYULCkXBYWdofLPU49Tzez3nB06O2F6n809OXynp5lBaFAxKp0kZaikMpfKq5aUR6Hmaus3aTKLizWrsM5VsBbNBq4VnSUpp3K9qlHoe7mI5XTVQsqFTXGOHwMtOEwgE1QV5qsMKTKanN0KY6e+6Z+5xu8nraQPWbtPRbUt2HwUQRO4XAwEEQngqOgeS68sBX73z99TTG9zip/ijr5cekqmRAoqKlnSL6JyZAWCaZzfNNZ1MFxrga409JJSGLKF0Ubn30cy8sO+WV0qWZakNNzWNImAzFakuJYxjmuQ2S7rDFTSLmWthrm8u5Zd6TKNAv1Se92YfYNnqzbmdNZjKZQ5hEcnYdh3UlasKAkIRj03M7fvIlSOH+NurHyHRz1YNhiYTuM7kLejU0Fm46LRXS+zGaG8rWaRqS53NS1S1c3VPqSg1qM+0fO/U9/HnpY82oq5FW+l0HbSNBByVFSGdjlwmyz0fPv5682NEeH2Ok46Emh6T+iO2Pa463k0UzA+q5KQIywiAJ1wjpEJlqzVFUS7kyIcP8R9EeH6MZESp0rgtJRO6VE1Jt3SXrldoWbJnYANJscl5dEp3BvNqUHT5pehelmatnM3ejlraQVJRa6o4P6zwhCGOwqDHJAzWtKWo0AKD6G5lrGN1l3jabetLYT9gj3ir0ie4qkNRjbm7SgWaYhloM4vU2Jonj46+cmvDRfxP1PP850YVbhSRzzYIoMti8wLReKkDCIpOyss9zG03RZETRpfA7hd6Su0JbxVUtjenpjcnh6LWoLlWLNL1N2h1Sw5A5Jm1k0MqEPhQOUBhwPRzrV5epWmAObfVuRZ0ryyxmdstFmcFxaUtktyGZTj6AUzQ2k0NM/B+t5ufUEGcSiS4yMGy7RBVlqqlSuTLKq2dFdYvZDY8XMnS3sKcxsVLznRJpvts/oWvLjOswepy6Z6YaT+8FpKIDQYV0wWwwHY00hIlnfDZaNSbqew6Aif4uukurObFQ6UdO8z0rMvJDRD0htKrmzZ823g8ha+gnX0Odso8R38WZvjNxW3KV5AMLatSUiwsIKyCUopWHRsY0ooeNRLlhBVtPSMMBIiVWWNr0e3NrbRUAqm4LMzMdE061MupStSAqo0zS4VU2060mGiZViWLw+pki+ysoxSaOV6k6Hd0cVjOlgtFcWdeSdJZu6CZXbl6fTZ16LHTzPocvnevkvJKFdDhVHKaqqJBjYJ632mdVUhyAs4qJBFUS4d5D0OXlyegSuy0ONZ0TNGW1oGSHFAltTeioBYBVzCVLY17WfQvDu1KsqhWbhBbQpaKYR3ArGIHkXikGyqeata3cdouMLbGMtExiaLjs5z77nPrn9nPjdXPZQyqG0DRFJkAzQUcO7XMGxi5JUttFoAApaUVINuQjEWcSGd1mnJksp5mbtOneeiGTQALSM5U9FP5Ue5S3VAFm84BNrBXROtXpLphzdWyyWzaruxN9IeTYlBTHmwlXJZ0maAsEgqJuTAB3Xl1e4usiryPrefND/O2c7z6VNszyps5IyYaDaS0AWBliYvIurpL5EsO4IwgCNFZcA+I0o1zTWb5Vrb82DOoh2ktNPQa+TJok9JVprJlyuZIqTbzyEIpROKJFw+QaW4Iu2daUZVSasgQFqXbXIBFCzpeitwYIRGG/r/AC+1Gl53WcPs53+jnaF1AZvriqrpOaczatBaRhVGsnUKjXAzTNIrXJhGIBI5MdE50xmxaJ7InSAXE6DLnTU10cplkXzucrBQw5dgz7cWs/Cs2blpnSJ1XS4HYTdwySm2vGsKbwWAus6VIZKUXXOrDBohNVm7yVyv2fl+mkRVx5nfFju5J3kuWwZO2xEy6bso9zyJlKl1KqSuxkTlFBAVQgyQGLFiTuKZBWMoqEhW43YnKoSV8wlB2nc2vLPFTSPCJlpm9ECzdU2rTuubeuYULRoGkqyE6S+zA6BLRkO0nJakGbNQFrRNJuyouVBl0mvT+P6fpufowezjtKNS876vnr8nYOYvvzo04bNDBTIpIkAdI0LWY9Akg2jDaTEgFKzRNZJaEOJIlhioh3aHS9RyGXtAN0W11IjrQyBDjC1srLFC6I5JvXPT2h0Sk3mZOMrWaQ0BUWaMDjkjlE0oESRha4FYPZEtRIGbHL5I1yyS3x9nrPO7lKjSmvH+x5WPnupx9TXX553NbJk5uGFzbRIyxizKKMcQepkYLTVSakuAhibgY075olyZlAgexnDaKNZlUkOsXfO09Z0InVqW7lPHWXOZ0TaX0DMVSlfSdqpdDMtKjSlrwwodBWaQKuky0S5BbHFCVcjpriGRVa6j0HB2a3F1+O6MFtcxxfb4PdPO1lRgml0uUXkRoezsdyHRJ6TKCpWKpUlQuMJUaK+kmqbsLDDLDLEmNP1uGWO7QHUY6Wi1sXGpUwGNnqpz69cbeTS3imkluS1NJsCayBJpugBEuSd2Fe1ZNXRDpDEvNDmgOqDYJu1RhAs5ZR2dp8PV1KqHctNOpyvQ4yplhtYUQaeuZCmMdVNYtpEuQ6TFA6JypYQVdxQCehA6BWWeWxKpcjHRP3XIjCvctay5c59LFm8HPVRVq3Hodsus7nqsGXslJoEUpNBToFtDmS5ccaNJupqVEgWl0BTC3DKMIEyXCust2iCQw2Vzu/PpbK7S9TC23SHpcAqUpOYaLCM2tpIqIZOkkqekrIKaoOBCbhPqQmwp8nRhU75lLUNER9K4S2+dkZbeVNZDZmtK529s1m8DHQU0zm1gybqwrsuIwrND1Wi0w4PSMnkRaEkw60WtWtGc8zmk1Rk9CptrmtWquND4epaHGVTNO9/IQccPXq9vDfWB6TEs8Vj6AUUgCMkkjIgkKtKG4l8xmWK5BoXRQa4Dm5ggBFQH0vnyz5c5Vm6pgUbS30RGb83GyMtqKBa3cpT0kuiDorNNCeSmitB4a1GWGfjqBDTi9g9F1qwEhUTkZWiiJaDQDO1poDDpmR0MSthIWsaOSTALq81q5O2k4esxaccOURaAFM6FDqNiSWh2SJeLc50noIO5qopWcWHIvX+c7taScdORrlWL89L1srDaOJfSSh6DNo3CDvJqkyS0thEp5NoGWiiYGGJNSNrDDUDSbUbczVWSxyk80FrPmxwEGtZYRZalA1cpEEVo8o9Bs3WHlaitp5DcAhhhry5ZUZg61LQ5YFVkFlc0jpXBLLOZaI19b54tLTEjFZqs0rM2RkNyFaWsTb9X515+8+Y2NKcyDztHVC5QpG4aWytaPSm0eUQLjkeZoXSolIc3TK1kr6qWmWUtXZfKhSJUxslBWEFeUXO75WpqlakiZkWADVWgl1aq0XG6sqBBc6lTXZRRATJyBs5Hq/MsrlxuLnL0nQy1z6zoDYXTS0jH1r13BprROL0wyFGmczGrRDRbfPTbS/RmTdTpmAo+Dyys8cJZ244hiZVpji6oOkKlNkMpbNmSiUC1VBiCJc56FzmwFm0OjNtzIixVZYiaDQ0sqnRwqpU3NZdLlyCFWP0yKnwRJ0HMqz//xAAoEAACAgEFAAMBAQADAQEBAAAAAQIDBAUREhMUBhAVISIHIDFBIzL/2gAIAQEAAQUC9B6qiOoVktQJakz3yIWsdZO1npkV5kx3TOTO9EqYshpkSGGjrRI5MnYc4kseJ5kKzYlkkUJyJWyIajM/QY62yejSK9PaP4PKgTvgNwJYYoTQsyw98yMpD0/c/MPAh1o4VslhRKqR48iSmdbZ4kKDR3SNpFmHIWFIliM/NI4bRZYyOcQ4HgJadIjhv7nGYsq09czumSJ4cSeNA5QFdAhlwPXWTqgV4MRabA4RQ8qJLJNzsRZkollI4bkSGTIk5Mjis4tEtTkfsMWdudO4sAjiCw5HjJySJTZHsOKOEDyI4SONh57SrEtPMyWmbktFI6OR0ZkNJ2J5UUSzK2R0+LLNIG2j9eYtRkz2xJXRY4nex6k0R1hit3JacyODsQlE4xZPDkeBkKEhqA6UODHlzP0pn6shZpHYVx/kdMDqrHlVoWpoWoxP1ESz0PV4ErISIYCOg/iIZY8keUx5kj1MU2TkdxCEWPT4nVFEck5lsD/RGkicmSZFoTJZTK9SJ6yRzpFmPNkcKweNadVh42Og6yMEeOJLEiRyUh6uj9ZFmSeg4snORHNkiGtMerI/VI6mehMeHuR05kbNh6qPUYHuqJZMD3pH7Z+qxzkyWLufmodUhYUz8qRLSh49aImyJRJ4LPGVz2JamRvTP8n+R1xJV1ndWK+BGpDrJ3MmdaGkSqOghMcjypksBFemEMA/PPBEeJWS4IVsS3PJZ4tRI5DHuOBwR/CSJ0nIVp72haqx6iciuCFkVn6VZ+jE7ESuR3ocEyyMh5k0fuMcoyHgIjhRPGSexHUSEtyzTpktPkODLLEj2HsFYyMieQdxLdnmY5pH6AshixEz8YWmI6a0WW0jVIrKiVxLIZDU2Ry5Mlg7n4xHQWS0Bi0SR+EfjpDriTSHji0ojVseyJPLiyUYknEjfE7h2M4bjqFFH50RacRwhYI8UsoRzrHqUUQztzyyY9GTLdISJURI4kiVlhzZFkbDmjvgO+JKER1oUWR0tn4Uj8KRHDmiV0ke8WnHlQ+A5QJ2xJ5QrmPJaP05EdTmLMmd0h5UiWWeondEjgbi0WZ+fIqw5Ck0WSLpjaFFCjIVdhK6Y7GSuiK0jqCPUdU2fnM/KRHCidSIs/jHpsTwVksBHQdJ27DtRKMTsQrhWsexDIiTsRLNmRlJn+zhMTkh5DJ5B7Bf0swpC0wWBEgoHbEckf0/MmfkSPzSGHEnp8R6Ox6Gfgj0po8LFio7Io9xXIUUWWIcRUEpxQ9SgeiB7Yo/TkeubJ4kmPS5oh2kM9o/ZiR1YuuTJWkR6YmT0gWMcURgieCz8uQ8ORDCY8dEr4m+4sQ8BCtodzJHUiWIyUiVpCtibR+iSyyWQz1MeWV6gdzLLCOrHdufnSFpVg6LUS5kcQcEh6u0R12R+lubSLMJs/MPBBEMqtHVYcLTew3mLcWOV4LJ4xPc7WRhIWHYfmslhwNkdw8zY/ZYtVmPVJkdRkfqsnno8yZ+YU4EELIiS/o8ESaLMknq2x++yWrMhOwd1pwmedkdPI6UPH2FOJGESeniwpG8jvZHLkPKmWObPz5CwUKtITOBGQ6Dyshocj8A6a4ksyJO1lWe0PUieqIhemLGTJ6YyenMWBNHZYj9KRLNP0CVNhDBtPIxTSP0kSzZF10yODueBnTIX8J2yZPT5MWnMrqkLEmPTT84umKRClk6iNhDNHeh0ocNh2WHCwjGQoRPNBjwBuR65ENbkLWWX5zJ5UjtkR3OlEsjYr1GYr7RcjqJ5DPSx5cyF1jHhbn5SK9NQtJLdOZ5miWQkW6wexMrriRUUctyWnH5Mh6Oz8ORHS2hRaJalsP5GQ+TyKs5SLaSzUGiepyOyTPOSghYB4DjsRyZnCTPH9K4jko9MCU4mwsceGyOK/qWMSq2P0kS1gjqW5L+kapH+juHEliH5ZDDJacz89k6ROJW4EYIuxZE42HXYeWQlsWZJKLZHHkVVsWlo8LJtkdRiivUWyyFopcSzWyetsqypMjUSzIlmUjZnkkdLPQfoM/RkK1nIq2PNAsSRGDZDHsFCRHGPCdex3M5s5naSyme2Q9WZDVESz0T1A9TIcjyzPHMXJDuOR2M80haVJi0vYeCRqFYRyUPOiRnuSwCzTRx2I5zKcvc6ESoJo9JDUJFWsslq7L5SZXgshRIrhMdEyeMzySJUn6MUPWUW58pD0qTF8dkVaVxHBE1I/MmLS5HSeqJ6zzyZ+eyFIqSypCprPFWfnxI46Oo7thZ52JHtZ6pirkeWI8REcRirNyeREeoo9IpHePPmeiY3I7GSy/5G9lcZMhjSP8Aw90TsgTSFaRwUPDicUIWSiN8R5kSeoM9TK1uLTkePYsqkSxJjypRP27WVX3HuHmM3kT1Vn6O5CMRqo90ES1KRHKsJ8j0bD1mRPV7DvmQnIrq3FjI6mTqHqEUfryI1bn8JY+5ZgshhyKqZksWZ/T0HUJI4oniJlmmCwBYgsc6ztHlEciRtI6GT3P6PGmKqQseRCzYu1EnnM7mbi3Kb2SHjM8rFhssxyOMLBIaej81DjAeRAllI/WP2GV22M9SR+oW0NnTsTlMjQR4FiiWRRG9I/QP0ZCzGchWFWQiFTJYkiWIy3T2SwWjdkWQzInvR2kYs4yHKR6pHrZvI5M4MnjlyOwRTQyVxbbuPGZDBZGKET3OI7EiGUO6Qso9iJ6iiWpCghSR6Ue0eQyVchohks/TY9UYqWyOlSHpcz8WY9KZ5oIlbAhjciOinZxLtQkxXn6Is8lkHOQ5s9BAjio6kKRJjif6Fuekdu4tzkQsFlsd5uiyAojTK7poWoSK9QZLJFE7j1k8lH9I0HkJVk2dSIbHMiQrJ3ncyfIcPpUMWCzyjxWKsWOhY6OLJxYp7C1YjqkmWWMlAr2R+gx58hZZPUBZ8iBHKRbnNkqmR01s6Yo/wzwxPAd0UPK3PKh6ciWMSkzsY7SFosxI/WI5DZLYdxzZOwd53shIhin56OhIeUT1FkcxitLrkekqyBXjyUWxZ7CvUIs8m5+Yh4KFinhHaTk/pXiuHn7H6zI3tjmdxGG5k4/ElkEnI/0QkzsRZEdJTGKI5MRtE4o4C0yTFocieHJDwJHgZDS5EY7FuQ2fltkcHY7CEhVwOzcWKxqSPTMebIeqErBY+49IPyT8+RPBaGxZhDVyGsH6EWOG54h4chafIhgEuJZYJnWQoRGuI6YDwonMnVuQxWSK0RyB6lIesTFnyO2RG+RVyJZKQ9ZifpJktmdcB0xJ8RyRGspwpCpZ5yeMieXEeYj1jyES1Irzme8lqsmVxmzfYlqJ6h1yZ1tCz9j9pkdRI5BJsugRrK4tE9TZ+k2LUEPMiyu2KLdZY9W3I6hFD1o/ROyRPc8rI6UN7E82RDOkPVJktVmSv3KqyEBxQomxYOZG49CJ5iLLiNJDGHUidyPURx2RhsXawkS1lslamKcT/JvAV1ZzgQyKz0QJ5hO9jbO09JyKqUbxI4Z5DmdTJQZblSP6VpoeryJatNleWeg4GNpbkYvw8x/iFQ/iFZn/ABrjG7IIakR1M5Vsjj1Fs4lcURwYDx4jY8lHoKsmRXayciyUD+G6OESVSPDEjgQFTAenC0s8BLEJ4xZSdhVnFWsEtdRP5CT1Dc4CxWSxGeIWNEliIVIrBrceELTmQ0pi0Rk9MZHCInfEUIs/PiW37EptkcZllrIx3K47HqEmyGnHTFGQ9yrEZDA2JPYjlM0/lOVFOxGZTeRtKj5N8U5rskcVvLKgj9WBVlVCuqLL0STO0sp3JrYjaV4DYtLFp6K6oE8aJPHROBKAsQnjshLYhqDP15H7TFqW5/GPHgSkdDZ+WLTSOCLCJziiWSWZLOZ2DiRZ6CGoC1tD+RM/SkRzGW0tk8RkMAsythzkymmQ6icmRxx4rPz5FtDR2nazmVSEiUCNLK4mjYW0cqv+VzZGf932MOX8SPmelcbJQRLF3Pw9y3R9izEIzkizKI5BXkRHYhOJyIQL2ytnFH8FYhXRPUTuLqhM4nAVB1HVEeQiWSyU5fXqZKbNmdjO42IQIYpHSiekksQ8hsPIJaiQ1YWpE7dyFaORP+lWmnOKIX7kbNi7WCeYLKifqxI3QYnWTZCKOyJj18pYVJOgyM3Yx9eW+HmbmLk8Zcj5XjcqKpfxEs4st3FFDnAljQZZhIlakVawLVBZhyOaHj7jwyNJ+aeLYckRlEjXAlGsnRAmzY6xZItQHqIsw5ltpPIYs2Q8pkGO09J6SWTIVzHOTIY7GpHSxaZuLRxafE6q0foVn6cB62W6m2R3ODJ7lUiF6HxHpiFpKKtJieCCLOB/DQI//pjV/wA6T5DDYqmaFm7PKq5R+Na72LJq3hOaQ5lZEsuEy3FJ1MqmiGEiWCOGxZkHcVzZXkllLZLdC1NlmQd5CxkUNnSbEclIhQKCJFlB52QoK8Q4RRzRI3J4g6UcGad8O505cuDlqLJXMdg72WJnI3IUnWjzlFBUzI5kUfwZ52eNkNOJVxiLWSGrHrTNCyF24gkfOtNLMtInqDMX5Xxp0zWJ12YPyNWY92Ixt7VNIy88x7B2kriNhTElhseIyenseGyESKiWbENR2I50WWYkDqrPyojxUcBwJzK2iKRZAcGRmyOoMepseQT3EmVWMrvRLUUPI3OolI+Caots3TYWLVf+PzP0O2JViEcNDx0U6M5FHwmYvgTIf8fFPwmCMf4vUijF2FQcTKwIyLvhlTH8MgZfwiRqHx2cBYKZXpKHp6J0Gn/yzEIHyrT+dEiuowqWjV7uNWk5rhCeYz1jyiMz0lUtzzipiTiSyiEzIydllXFO7IRIWk9ieMKllmCyOHI8LFjFheO07RHMd56IitiyvAPzx4JZpxZScyu8SOaQtRZ8U+V8iMhwMrSIsz/jUDA+MRiRpEhMZdaY2SxZIsg7yNojYdZ1Go/GK5msfCZwJZH9q1AjqCNGy+UKmbGrYUYWLNiX6qyuuNlfyjHJVEoFGAWYZ0IkTkRpLajcoyDvPcizP3OYmNDkRzGLNJ6gz9JnsOe5Gkelpj03Y7GOB1HhI4pJEcg9A5nIox2JCifnksZGyR8T+W8vrLj/ACk7iIyCJigOsVYoCgcBV/XMUvpxPkfxSNhl/HJRLcPY+GZ/+MaZE/5HwtrXIpifGrN4/JMiPDuO0rS+v/k6zgiNpO8UTpSZuf0t3IyFey6/chSWSYqyyn6icyFgmTrHWhXntG2dR0nWRytha0LUmyOUPVD17joHilFux8d11WQ2MjEHM9RG43+ofcWISNjY4nE2EvrV9ONU+LbmhOVd+DMgz5No3bVPDIYxhZvB5U3KcyETqaJcvpshPYlkEswV5XDc8aHKKHqjLrtzAS3ypSTLaP8ANeaO87mSI0sqxCuQ7TgdQqSERVCxjxnmRKtEpIlcOw7PqNpG47TDypRehfNmUaipK0y8MgyMjchITJEWR+t/pfWxsbHE1LD2dkTCmUsR81+Mbr0EpiuPWY73PYetjyhzP/rrPAcUj2M7JkMVjiUxR5ItWYuziyNjLdPI44qGRo+naJDqFksjmI9hPJHdI/orWdzOw7yVx1EcUcEbIVaOcULL3FI0H5F/a8vdRyxRTLsHYjMgzkROo2IkWbif/bOxeSugabMoImx83+J8Zy086SFKJUxJOJGJ5TyDkhZBfcytnWkSmK8kduxzbKNycUOwuKbCOFuW4uxVIyrjtIXshjDoiSy4IlqJLKZ6B3DtERgdg7SUjpODJbnnP/Cy760T5W4vTs5SLIGn6nuZD/sCJA2NhfaYn/03OZquDuYdZQR+tY01WV5TadkjkdT+kRuZzFQTxhVjtFeRtHIZKv8AlU9jvHlE7h3ncV5LQ7kzhEvpTTwyvGJZTEQmRyCdpKtko/TZzOwiiB6z1iyy217c/qFQ8cw7nEq+TWGj/It51WFciK+o/S/6qRy+9jiXYv8Aa4EfqR8yx9smFRNxOZx+lNG6FMhNFmOSqOs4nIUSmsvo/sjYjEhWJo5HP6nlFucYX/v58UXwJ1HZsew9R7R5TIwI48TjEncSs+uJGkhtwdaK7Nj2iySsVhiZnGeg6qpJMqySu0Vhubil9L6aExP6X00bG5yJzPmGbyyHI5EYFaJQGQtLWdhXln6JO77ciO5OxE/rc5G7IWEdy6bJ3EoleQesneTJUDpIYDPyGeEdB0HmHUOJsRrKK2WQOA0LHFQWWoqzS49hj6qyGv2J4XzSRh/MINYvymtn7MDH1JMhkEbTmSyRXCtOw7BTORKwyNXgi/5dE1LWpzNWxf8Ac6iOMORGZK8bGitk0M3Is3OZGQjtFYdp3ERSFM7i+4TRJfTiKB0lWKQcET1Qnqh6zkOLGI2RzRZmjymczkczuHIUSukrSLKx0EKimI4kYnLYidhHKZ72PNZDKYtVmR1mwWpTPfMt1uQsjchI7zN1DZO4myMhssgKI8cUDj9SRKJ1nD7TOJxHI5G5yFIjXuah/wDymbisJ6mi7UmyKZKROk6iGGbpEs07SMh7EjYjjCw0WjYoCxhYhConeiuYoEiuv+zpPQQ+na0cy3M2J5zI6hIWqs/TkfoyIZzOxmVF74rKpjZn5Db2GjgOBGZIjMZKRzORsKI4nMeQiWYSyBWG5yGJkJHEuTNhxOJVEjJIepxO9MTielFk9x0nkPOKkcCUTYihwFiEcL6rZPJLLhIbFkizGe9ksvcoZCkUiUj2Is1M9iFjxJwRKs3OQpEmYciLNRyGKRzOY7TmdhZM7Tc3EzkSsOw3OsdB5x0nV97kIjQpEIiqJ07HMnnD/pHTiGLsTgcSjHJU7DsHEVYoCROZPJFlnsZCwcyxnErrLKhs4iiSoKcQjAkOAofUMXco0hGbiJDgInWOtkIjMOBqOX/e0VZ1k0RYjrOB1CrOk6RUEcc6yvGJMdg5jyRZRumSoEboumJitKKy3I2JshgM5KJPMHcV2HYVMiSsHYd5ZcTvO0skKJCn6nI7BM7TtJkoEYEYnYNjQvqFJNCvFkHqFIZKf1Tjmbm8U5ikVyJTHeQkcjsOQ7RSIyGyVg5noJ5B6Ds+kjpNjkSkSgRRUcjt/thPGe2TmsnP62K4EcVlC2LWzZk4jZC4cDzkcclkInmDsORub/VZyJROwVpyHI5kIkayTHIkOBsRZNlf/tNZdcZVIokYnEcBVjN/riKo6zqETgbGxKBwIxI1HQcPps3IsciFojcjYSuY5CrIM9CHYiFh6SWUeo7dyAyUzmTNiMCETrGjiKJGAoFkSMiDExkIHMnlErDmbkhs5HIUzH/qx9MW+o7IUTc2K0LFHQcDcruHcdn83IWbE7zY2IoVRKocxWnYSsHWOkjWOB5hUjRyOROBdA2NjchE8zJUMqpLCEhskSYiOFuLAFijiNEjsO47TkOBGAqyMTsLLiTNjYR2fbiOk0+ZGO5boBH4+X6XGKbHYQ/hyJSOs4fXeV2lthyO45EpnYQtISLWcxfXYSn9OR2kRw+o3F8tzgJfUBSRPJQ8j+HIkxHkK9NRyRZllthGRdIZxOsjQRxCWxKRG8eQcvpxORuOQ5DZETNzGn/abCeJJumjiZVv9svLGQWxyGiLHM23FQQJ0nQSIs4nAjWORXSSrNyRv9Nmwq/tMVBHHJ1onkIlmleQTbZxKcYhgM4JGVfuWUbRWWehitI2fUKyrTx6aTikSmiWUSymKf1NGwiMRwGjmN/W31sNiMLILNQSMvLcnGJOBjxOBXQTpPMeQjUjrFSzrLImTURqOsURkEOY8glI7Dn9Kv6ch/TMnJJZY0x1EcdlWCyvTSFCRPUEi7V9zsKf/VRuS088BHEOo5IeYkS1Jkstk7TtNyJUv4iVZKg6Bm42NnEUDrIr6SOJKZJHA6yuszaopRkTmVWnYcxLd8NnAmci7ZirGjmbliORyJEkchs5EWcjY4jZGtM8aK8JCwULERO5Iv1MtyWxYzMfTCOmpHWiGZ/bLiWSSyR5Y7SX0iRGJBEKDgczvJXHYP64nD63EhQI1DLbBTEzmQkVIWRFkaC2ohWdhZIx/wCO+w7TsNxSHM5jZubkojRuTNhiE/rmdhz+kPK/lmeX5bHuyOOUYh4Nh6ikW6iRzSmZbqH9bFUcTrPOWYZXAjEWMQqJSLsg7By+tyJx+mxshEij0onlHcTtHEcRIpki+f8AKNPKSy47TdCtLCMyzc5nMT+uf1t9ciEiUTcjEnA2N/rf7Vw80t1UT3OIkVyii3WS7ObN2Ts/nWU1fydC3lYcBVEaivHLscjWKRZeWZpO0Ufps2GQmNm4jibHEdB1kofUWciU/pZA5FMycfqLOX81DO3faf8ApDEFgjoGxzJXEWRsJP6bNhItY/rc3+uBVFiwymglhMjBIs2JlVIoFmGeEwMRbrHRKlE7S64UiLKMkyLidxJsZKJwOIofUoE6zicTYSEQrLSVgiQ6zqOokvpfS+lE4onUTgMjee9jzWWTY2KQyNhubjf1yFcWyN/+vMjnQP04lmpEsxllxX/5HJRXlf1IhlFuYYed/YZW6v3OJRhcndhf3rFaSvI2HeTkdZGgVZGBsKA2ZECD/hIhcTyjl9u03IyNySJw+9xCkKZ2lsjgLGPOeUdRxHI5/SNjkbHEZ2HE2EbfcTsK0cy6JivdWYp0jtPMkrakRmaa/wC3w/s8UqTJwFJNW4u4sUhpZLDidUSMRo3IXF9qHYRLJmPAcBo2OJ1jNiRyI/SZJ/bFM3NyTNyBy+nMbOskhFOLuOsdZOlHWKv6sRyORuM3Nz//xAApEQACAgIDAAICAgICAwAAAAAAEQEQEiECAyAwMQQTQVEFYSIjMkBx/9oACAEDAQE/AZIiCYEIQqYzIjlJPKZtk06imOnIxj8OlIpNmxmhQKKZkOmOovIdZGQyJMiZrEQxwMmoNGh26kREQL+pHePhCqfS8OfLtzSpVFzarIdTArRiYiQ/DHA6Y7Qqmn6Rjcxb+BjEL4nJEmVMfwYkQKl6QqY6QhCMWYCNDMiIZiL2/Ex4xF8M19GQyaQhCMSIFTH8CFat+VBgfRkZSOleRkIQvLMvTqIi0YmMCFe6Y7Y6QqXljkyMiR+FbMjIcCi1WzZsdsd4jFaFS9YmNMY7fh06QjERoZkORzbkykY/K86FWjRq1TMhm/GUGQ6ykQ6do+hjGO160aEYyYyK8jIYxjMoMoGbFNv4NGhGIoEYmIhGJ9DNGjVoRMUxmxSOmOLm9GvSMRRSFTMhimnSMTAwP+JGI4GZGQ7yHFo0aMoH5YyJpSKkYmIhmQxmqXlCtoyuBwZeHbHSp04HBM/0bN2hE0oNU6UGvKgUGSMjLzHEXhmRkZGVIxMRVEGIx1kZH2aNDpCEL4EYmPpmV5D86NDvRomTIdIkQjAxFFrwheY8sdrwrRiK9U7YxjtGJ9GRlcjqBQIVRUiJjxECqOUGZMjPu2IVPxscmQ7QjXmfCFag0avXheGObQhSLzocGjRoQqQqQhQaNCMYMYNEjHNbEKLY4NGjRIvEaMjIY6QhReqcDi8RCitCpwMYxjHIzYpFJiYigxMfOzZDFIjGBenA4HSMZMZpwPiaNEIcDgW/cDgflCpGJjJibNivV4i85DmTdTP9GxCEIRoV7N3FqtGhCFUTPhQLwjduo8u3HhmQxjGM0IxNU6xEIRjSIg0M+zYzK2MdoRPGTE+qXpjMqREGIjExMRTSEMYxjpUqQheEI0apU7gdZGRkOBk8qRlA/LpGJjeRmZDpGJiIZkOBwTPh1scjNU7QoFAoNCi0TFMcketkRMmEiEIxMTGDQiOIoHB9mJgYEwRHhCEbqBGJiY+Mj7EKBQYxU+I+B0hUiOJjezZs2bNkca1SJ0OaykyqJHBCJRMGEH64FHj9TI6yepnP8fWjEVQSIkYyBCEIRu90xybHJkZDImsTEwMTEVMcGQ5HbMjIzMjIytyOSP8AdO/sVMckSZGU0iOLOPWhEQRFc+qJJ1SkQpJgxt+GbFJs3bMj7MYMDAxVOaYxjtC8oxMTEQjQ48TbGZQRIoNGrcUzq4E8bipO/j/JuTJGRleJiKRVFqTdSKRVEjGO2LyvLJMjIY6RiYC8IdKkIUmMik2RSk48TrjQjmog/dEnHZIjlAkTBHEV7GJmJgJWzInkZDvZs2RaMRC8IVoxFBrwzJGQzcmMmJgY+UfRkZmQ5GbOqNnEZ+T9COjmtHKWRJJybIMqxkXhmXwYGIhGiSLdQMdTI/DHX6nBPXMCpCjxMjGSIxFIppjHWJiI6fs4Eyd++JEH1s6+TMeX9HKdGRnBEwO0K2MfhCNmxybEKpHNM0KBVFImBeOrlH0JnLqJ4TBJM1DFMmEmBgYkcDExJ4mB+o/WKYHJmZSRJx5bOH0Sf6JhDPxO3Hs4n5HGOPRPJHdxnh/5kwIRiTHjZsxEIxJitkSZDHBMwMYhCtSKRDGMdoVQcOy564J64I4SKoETJEojmZmXhGJy4M/UYmBidcuIOVdkTkKThqWdX/d08JP8116jnBkZDkcjGyI8Kkfd/wD05RH8EwYmEGECp0zQzIyHaFU3kZDk6+dJigkQiIgmDEwMRCEL12cJ+4MzI/H5PRJJ2Q7/AMT+S+qeJ+f259fLjIrd5D/sygdoYyK1TGMdQcf9k/doVRUiMDERiIjRkM4cnFIRM0hEfL29T3BEo6OW6kkkmZOn8nn0y+J2/kcuyXI60aHBoQjERsilJicYFIjlBPF/RHEniIQiJJh0xkzbGPxAjEQiOSOPaMZOyI+d12df8imJOudEknLhkYoQjE/WYmBiKmMdKmPzOhkzbMjIxELwqQqdMdquLgif/TnZy4nT9Ek1z/sYxyOaZkZVEGIqRiRxpmQx2hCkxMb2KTEXpCp1ocGzjwVIgkiSZI+BC8o58Dr1FTfLipEapmhWzIdq588ZMtVMmRlWPiK0aNCFeJiYHHr4i8QSKYpfA6Xln3U1B2akY/cjIkdMyGSOpRiYiEIxgREDkdYswMTAxpyORCpkETEQT2H7ZM2ZkUpIgQhWhCFaF4iR0iIO3xNqkIxFUSSRJlBrzFukK4kyMjMyGODKPMDuJIj+zKDMjfwIQhCpGJiYiERwMDFHd9juRCqSDXlGIvGQxmyWKTd6HeLMRCEKlSI14VM4b8waFFMYxjGMyGMyGMZz5KCXaPoftjNDgyGP0iYEIRgJDg0I0OlW/UUzIyGZqNHHmR4ZHieSM5P2Sftkz5GcmUjI8c+T8M+xWvGQxGJgYi9ZGVMyJkTMZFcQMfheH5XjKTOTMjmZQZQTyg/afsg/ZEmifHDx2cp/j0hC8IQopmRkZDGPwhDpCrIdQJkiubQhVMi95DpVNxwOyI4kSRfWq4nbz9MdMYxjpjpCMTA2ZVsiPWVIQhERNTNIQhC8RHiBWvM+ETAr4cCOJz5KNeEYkwIQhUhCEYmJiK3SqCR1JsREER5y+BiZiLyxk8x+GMZsj11wyOIyYOUE1HKSeU+HT9MdMfuBH0MmaZPhVAvCIgRI7YyZqIFc3jNu1XD7OOzA5Vy+66ur9knPWh3jJjNoVPwhXEoyGMyHckkXM+WRHhjJkZHhCpjGP2q2Mjls65rn1TP0ceqf5O7hERXV0zy39Hdx2K3SNEDEIQhekKkR6dOlJBBEVNTyGbMTEgm2MdoXwImkdXIg5dcz/JEYxuTs5ZSdPW52dvNagmfldTIx+VTHbtGJECpmZlJBIheJ8oQvL+J/0dXZ/BmjlMyI46k7J36jYrfl0hC8MYhWjRFMyMzZjJHA1FOLmorEVIgm2ZD9umOolGTJkiSDt4whVAhn8kfYieM1Phe0Lw/GRkNmMkcLnkTMmxCMTExELwx+UK2MduoI4SRxI4yYkcT6JmJipGO2ZmY38yMTEQjRJiYiueRPJkcZMReWMdMYxkC+GKkgxI0Rzgygia5ZRJwZySqRSQzYpEY2vlgfjEgdzJuSOsxVMyNW6ZM2hEcRe15fpmaP2E8x+NGhjGZGQzdIiCTK4ion06ZlBPIykVMYxkGoqPSMRD+VERbH8qZgYi9LxIvSFJjJ+uTESpCEIRB+t7JiufKOPt27VzaF5XwqkTbHcfBNP0xjp+ZhDqOQ3WqmJf8AxEhCJHBPIdQap1NsfpfKiBVFqZ+rmF8f/8QAKREAAgICAgIDAQEAAgMBAQAAAAEREgIQAyETMSBBUSJhBDAycYEFQv/aAAgBAgEBPwGyQ80LNln8OiCpQovTFikdHRVCSR0RrI/+H/wp+I7Gk/ZVFCp39H9EMiSILo8iLIlFfwhk5E5Cb+yslCiGoJkSxFjA4f2QUPGiGjtj4zx/6eMoUEiS0FkyJHgVZ1v+jv7K7hEizRdFmWn6Oj0SeQT3YmSop1AtSXJ1BC1JI5EhnRRfh2j+iGKdQPEg6EkNnkR0yiIg7Ey228vweWX4eRiclCmkPGTxshHRVDxY5P6LZFmShOCdOCzJZLJZaDyktiEW+CGdk76PRZkj7KsjbSFBOuh9lR4lP9Fh/pBB0KNdHRZFizJJPZDOyzJZcXISmVI02WLl0PlLk5fR/ZQ8eIxPcbbIFiNCaLCyRKP5G8TyI8i25PZ0NLaY2RJ40URCOiUT/hJYuPIsRJX/AEeB/JKG5I3ZizZfS6HkWE/9+HRUcoXIyZIQoKorBYTkeJ42UyG/wsyREobWqSLjJgbYiBoqdDy/wt/gn+Ill8kWyE2OPsaR/J/JCIxE0i2qlBuC6LIlHRYnUCRVM8SYuNISR0QQSl9FhPTSKohEP6P6OxCaJRKLYnQ41A0iEQJFtSicSUPJFizJyHJDOzsksWZJElSh0dbemihB0SiUeSC0jWQsf1nixPHghLH6JRBTEriVRGpJR0ST8XJ2dkMhnZJOqsoUxOkSSdjwk8YsP9IRVaqURVFSUixLZDIZOoJRcn/CxLIY8WVZ/RYuXLEkFEUIIQkPGR8Z48iv6dIsiSCFqTrc6jIllhsll2XYsnqS5MjxIZ/R/RXVizFySeyrKkIsimRGRDEmRqCBydlWQM6IWrweTIvkWZdly06XHJCQskdEak8g+Rl2xrJleQpn9soVPGRBKOjxlWdnZ2f0f0UZVI61GoKkHQskWTHIsx5nkJkSTHgUIOzskkqyP9IFkX12VI20yjKQVZDKlSNeNi4/09Ek7aZDEdErXZZjzYsyzLZHYkVO/otkdnerEibP6KSeMqQNEFoHyF5OhRqp4zxFCrIHlB5C4smSNjyZDFiQUKHo/oSZUfRLLQWJIFiyrI00eh5nkLkjTJZ2yCosFqCrIP5E0QOT+yMyj002PHIrkY4v7KlSB5x6O2Sy0D5Pw8jFnk9PJFtVZWCSxZliUShpDa+jtixZDKnjPROQm/s6H/6P6G8y+X2LkHn/AIPk/wAJOyrKsUnY0dkMozxsqUPQ80eRHs8Y8IH0W0kQhoeTJepJIR2dk/CUPI/pj4jwiwggyTKsqVgsix2RvohFUVRRakuWQ8svojJlY9s6OhEjZJYlnf4SxvNn9nf3qTsU7lHTGSPBMoiF+nX6WRbEviPP8FZiR0IcnZ6P6Fi/sktp5CyOiyFmWyP6ZBeDyv6G8mf0KSCFvJ/hZjYmtQyGNMjISZY6LIsNJ/Z4l+lII3JZisf/AEj/AE7/AEjIpkRkJMcosx5MlkMUolnseL/SjKFEURVCwRCRKLIueQsxWLR7L/hEkQS9dfh0SiUWLMWW1pkDxZB2WLnkX4OGVyK5FctQyuRTI9EDGJMSJ1VsqzoWO5RYksPNFx5yJonEn/Cz/BtjxyZWCRMsxSPEqxYlCEhtFZEsV7LL6LMsPMvJY7PRY9lEQl8O9SdkM7LFmNnQ0QJMllmi4stSSTiJMqUOkMg60xIklnZBDKsoyhUghMoRBDE4PIycmQPFnoeZYsh8kehcmQv9JxH36KMWB0htEL6FxHSJkqiEVOyWWFkWR5CTon4STqEVQ3A8h5MuLIeQ+UXLIs0dIsiUVkoQQyBnbOyzFJYsxMlE6six/RGWuj2RBZFj2PEg8bYuIpA8GzxsWB6G2zxtlIERJC0xIksSQVPGeMoyp6LFyxMkFGeNiwZB0ZDW+hQdaSyKsggUoeWRbIWWR2diHkWFkSQjocLSRGoR0WSHyIsiyLF2XY+TL6Fi2eh5jyYsciv6Xg8hcTLE6TGyxYT02WFmPMszsckFdSxtlmLIkkk6HiPEqRudQRqxOpgfIWkR0dEotiSi2IskN/g2zsllhKSEdHjTKIqUZVoyeQrCbQ+ZnlyLNkkCxG0i6PIkLmXosNiyQ+xGWZiLE6GKC48mW3ZHRKOhJH8n8kIoUHgePVhZnkHynkY8mxSQV/0oVRC1OqHjZ4hcRQrBJKOmRiTqB2IyF0TqhRGWB4yiI/ByizM+QbGxssYc7+yRFkXkkTHn0J6/9HZ2StKCcRQyFuknjO0eRnmZ5WX1/KPfoqzxlRYkHQ2TqdrI8h5R5iyZI5KsqSdiW4IHgypZk5E5EvUMhlWcucF5Y9ZD6Ef8fllVGkiknjggZJiSjrTgyxRkJI6OjolEoknTxKlURrokk71ZnZD13qBYHjPGUKakuXLEyRuCyEyR5lpJRdEpnRU9FsSxy5dkwY5PIWDM+j2NwcWcZSS8mLNIy5fwVvbJEkSjokuLlLHsghFBYixI10dEosh7WRYuWJGyzLsmdSWLsTZLFLIeoFgVRCOkeTE8h5B55M712SSdFUVIRKOiEcjjE5Pev+M4E5ObCTBQzl42Ye0KiQ0m+iiRKPLiPK3piEPUIS3kvwU6ktA85LEkMxX78EdagqQJHS3BBBA8qvs8iLEsksKdQLE6+EvTS1BUiCSSwsjmagz96/4v4PomTLD7HVqJFxQyBcLTkfHkxcb+x4v6FgzFssSJkEMSIGSixYbQoHBCJJFqNyyzRdjbJZ2JizRda9EnKmyYFyEyVKlSrFgQiuJ/JKQ+ZHmReSV9k4llplTxniM8GU6M12JGDhiykqcvC3izhduaphksvRii3Q5FmLJFiUxpCgVR8qMc5Mch5EyQhpDKkMhiTIYlAsiSwjosiyJRUqVKDwPRJJJYzwT9EEtGPILsnHEtJ2OUSYrroeM+x8KPCUaIf3qRZMuxch5H9HlYuX9L4s5fb19HG8ajyxRlnKg5scuHleSP/wA3+l2VKDSKIgqx/Bns9noktJJLZjlB5B8p5WWJ1ZomSH9FWUZ42Ug7RYsNsVirKlRYkI6RljOk4LsU/ZZCyHkxMfIeU8hcuPIsdDW02ceeL6yHwnjR/wAjEYjjZJk/pH/K4U2f8XGjLSfQ5KFR4v8ASrKMXGZYEMWoTFiPo/liwg6Fij37KkI60yfz4TpoeJBiy5cueQkiTxnozWrQXMez0SSMkWmxvUkk/Dg5v/5yM+G3o5+NwZIRh0xYSpKoz4cc0YcKxQsBo7ZDHjkRkSWguSSjIllkLM5MmYQ0LP8ATHNTqyLLVhsa6E4II+EFR4ERpjJLkly0kGXGVFghdGWRYsN6TLE/9XBzT0x1fs5sYyaEI4+R4liSxcy5YFyv8PMeYu3qrI3I+yjHJbJMlbWb9bTGJFJKFhZFiWdnZ2KdvTxKIqiiOkN6lZD6Gx6gggj4T/0YZVZjl0f8hf0QLXH30VKoqiuJ0UTPGiiIQ80i8jyJkTSLDzP/ACFxj4vwXCzxQLEy6HyQLIeQshZDykg6JRYsSSN6kknUEMqyrHC9mXJ+Esx5Z9mQh4wYIen/ANvFyR0zm7GhLTcCyksSzseLFImydVQ8BYfpRDUEo6LEyIksSZGWElGhYsw48iiHGI8mxKSIJJPZB2OSSTsRYsjyfhnyZD7+EloOPktpjJ/7p0tZHEpQ0QtP5MeLOxlUUX0ZYwYta7EyxYklF0vRfJ+iWZshLcosWRcWWoRCG0TqD0ZYvJnhPEh4JIeBl0M4x5ouTuSSflPykkbOJuCXpfC2pLFjoqPASMsWUyIa+EjOhJMppk/GjZ44K6hkEEECRkhettH/AKHg2PjFp4sXQ8iw2WJJJ3JJJYsWGx5Fh5nCv5+Mj0tQdnZYsXgx5RZocMhFUPjRRFEUxMMcfo6P5MkipUqVR/KPIi8k/N5DyJJJJGJGagjSemipBXS/6JEtPWGNmLUancCHqdQVKHhFxlBpDGdjkebRxZdksliY+WPQs2xpmWORMHbFiSWJJ+EaYyCCBI8bftmXHC6+E/BrSxkoiiPGiiKoeI+jFyPUHHhHekySBoQhkolDRUqV1ZF0XHyFpJJ1U8SFx11UqY4HSLIlHRI8hIjck/CCBaRO2kx4I8aKIeL1DIKNi4jxwd/HkEMlnDgn73O508i20ySdQVKlSpUaKiQiYLyNIT0+Q7YsR4DRA3As5LE6jcliRqRItufhA+t9/B5s423poWuSdZHFxdSUjUiKlSCCCCCNLUHRKLIsWJ24JLQV+x5GIkLDSZYyZI8l9koWElUNwXEyxItSNkHrTYshPUkkkki0npsRK1ByZr0PI48U32LWWscySzJLEkkkkklixJL0tyS9IeCZXIWP6TijyqYRYnbnTwkWEakY8RC7EoJRYn4tGOJjgNDx3UWBUcDJ1BBJy5QjLISMWYZwWk9lCqWmiCB4sS3Oo3GoI3O8hZNDybKsWAkR8HGmNk6mCSyRlmTqNQQQVIgsN6aEhEkk6qLHcHIpRl0PIwJMBHLyx6MO/hYTJ1ImPc7sSTqCpBBXUCF/JadpDHpiMmLsQ+yolAlJA9ySSMSKlSoySdJfCEQZLo5FJEHHy4pdoz5V9I4M8myEcnJjicTLE6a1Jk9plyxJI2LsjSRKJWpHkMWmpMU0JECG0SNDfY8vogxQ+zHER0POB8o8pFOoIII1YsPMeTJ0kSSTqSdcy/BmPIsfoyzu+kcWCwxOXkMVPsxUCJJFtiZM6jcmOO5J+NSpBUg7FkSSZMkkiRcY8UtYvsmBvVRYlTo61JYsSSTqBYixj/q5uP7KSY4wSxnEiDJGP+kokbZ6JW8dQQVGnqRaTFBCIGydSY5DnUknsXGQiyRlmNvIiPR2hNkEaZYeRJYnftkFRIjc/GCCpBkpIjTRkzgybZJIydLpaZhl9Ffww6JExlxMggjckjZ2QyGSdikgXGyCUh8hJIlIsDKDKBZFixYbJ0vihskkb3BBBAhEDHmh5Ief4WY8x9mM4vokSkeLMsDFQZTl6McGeI8YluV8Z1IxabguXLEisKS4+RliT2LBmOKXsyzSL6bI3BBAnqpBU/8AEsPaI+E6WpMuzw/g8GRGsKHKsBKX0THRjG6oTQ8y5Ykk9lRYjRJYaMdp6ZBQjWXIOcvQuPvt7xxISHykyMWJA5FIsNRvH2MkWQ8iddiQhDZPxjTZO4PGjxHjQkZEnZ2OWYYMqVKlCqGkStSUkXHAlGsmWET8YHiQzwsx4jxpDzO2QUEoPZmvwkkkTG9PsxcDyQ80SLSQtz8UNiyG9JEf9FSuk+yREljyF2TuosixJOqiRHwRJfFHkxPOkPlbPfw8msTk79GWVPZjkmSWhNsxzspLbaKiQidyTrFj22W+b0iNyPIb0twSTqCIJH8IF71BHxgoiFvLoseysCyliGc3owVV2LIhC66H0+xZFh8onmxLL7FgxYDMhMesTIWmdEk6WnmWJFuTLa7YuiSw8iSSREmfIsWJyWgxyJHmSJkk6ZJJ/8QAPxAAAQIEAwQIBAQGAgEFAAAAAAExAhEhQRAykSBRgaESQEJhcbHR4SIwwfADM1CSUmJygqLxI7ITQ2BjwuL/2gAIAQEABj8C+IeIaMomO4zmafEddTfwHl4JIrGvMzc1M3mZi/JEOyNAvBTKnBBo9RvxNT/1DLGMqcSsUScTNFxiM3NR15l1KwJqUgTUaR6qhVYDsrxX0w9ikxotRtTKhVE5IemGXmbuCr9TteRT/se/udrQ7XMqmpYaZZDNzPzF1UzmYdMHiKzUufCoylR0HVfBCnS5l9C5miKqpmi0HiXgNHyL64dpDPrP0HReJ74ZvMzLoXGTQyl0O0MpdB1HXUdNR0GQ7I8BVYS5QrEg8yilyvSO1yGUyT4GSWHuVwzSM6GfzM0Q8fIddCijroU6WFSqaHbLmTzMvmNhcuNEpSBRjdxKr/ke5RClPBB1wylUkPqVnodv9p2xojLzPy+ZkQywpqV+pliXQaOHhMzf4xD8lQc/0OmkI6aoOhbBjIMmGWZk8hv8i2uLoZ04GdR5+I0Go6J4SM6/tHTig8Jm5mZdTN9TfwPtB/8AIddRuZuM8j8xdC8Wg0XL0GVfEaQ445Wvih+XCZYUN3ghn5YOXKoVRMKLyLrgyaDFTMuhmhTQzwjpoVU3lEQYpCbuGGaRnXQzclLrjfgPGZotB9Tf4Fy5fBz3wzIh+YOql9C/JDs6jwjnsN5GXmMdvl6DxmbmOX2GmZUGh0Gh0xrhSFFGgMqcDIZBik8KphmQzJgxlh0Kci5fBpmXnhmQeEzIZzOvkOupdSkHIyQ6H8JmMw8y/MvzKJFEU/DUyqZTIVknEpEmx2h5aGdeEh4lHHK+RYsXO1yPUeEzIZkHQfkZhyxYYbmMpSHUZMXKFJlUmXQczDnZ0OxoWKKicDOg6anZ1HTUzpqZiqphVcLDDDINCOmiD8k9MLYMMhuKKmPaKqpmiHi++I66HaUpNOJmXUzcysfMccuUwqqamYdB0MqKZZG7QdSim8yqZTd4GZS6jDDGWZSEeQ4xbZog2FVHVRjKMmD8zPDqZ0Mw6mYfGp21Py9VPy4TKMnP1GL6lUnxMnP2MsRSFSn1LnaGU9iq8kPYsOnAYy4sugylylRhlGKy1HM6jmYdFwc7S/L3D4MmFB+Y/PCqFhodBodCyD8y5WZmU7Slz2HHUr0hohlLa4Pj8UUjPyKKuhcYoiJhfCo2DlYtEL6F9DtDxYMijQnodoeIvx2GiLoPFoUnhcuZdTLDpjVR54NMy6GU3DlYkTiZ0XwKTKTKoMoxYtjcuVmNyMiHaL8SqyHVeBfVD3wccc37Fh0LalsWxymWRYtoOvkOupWJdSqmZCyjQoMmo0PEaHQaEYuVmMpSFONSktC2iFVTkOi8cHKJMYrQzDrg6IZkKrMymUyqZR5GZFHGGwzLqOqjGVFKwmUpCmhuM3MzF18cHHHwzDrhWZ2i+Lrg8jMo8zKMmw+Nhx8aqg5cpMpMuXKjl8ajmYzDLEfDAieI3kfFEnhOalEmNDoMi8D4oYRkL7TqOZiqwjpqb+JSZfYYyjYMg0J7DIZRhk2H2GXadNh1HHHiL8RsHwvrgxcaIy6mWEZD0GUqo0zKmhdNhj4Z8C5VFKoWKYsqmSXio3MuZh8Llx4sKIOVj/yK/iJqUih1HQthlmZDKVgKQntsNxvsVUbHcZjMg45vGPYfQ34W1LFE5DDH/wCUHl4yKxT8CiKVilxMxWJSsZ2l4FIFXxUpDLgOViN5REHl4Dxcx11KzGRfFSiQoVi/yG6XGhREh8CarquwyjKMplUyjjjmZB0HHHHQZBkKUKqZkHQdcbfMdMHHMxmLjc8LlysiiDjmYrMZRsaQ4sZTKgyFtcHxrUymUbC52h4h1HiHi4mZdt8Kj4PIqqrhRNR4U8DNMcYbCwwyDQ7TFxlwqpVRlKIpXmqIfCkHmPoMNsV2GGQZBtm5dC+2w2xfG42w+wyfIbG+FsLlEMsOh2caDjxal9cKyLaFORvGKqXKFRpm5B8G2qSxYYbYdB0xsW2WQbG46SPfFhthjKZUTB8ay5T2XKDyH6hUuUkmDDGVNDKgw2xXFhkMhlGw9yoyjYMMNzL64XGN2D4exvG5DGWZlRCqIZSycBxx8aDog6FlOzg3MZMKFjLCbsKri67Ni2xQqVQ3G8pCkio0zKMMgyYVxcf5eWEbQbGxvKYVikUrg+L4bzKMUkm1WeNtm+FJaYsNUklBOlGvhCkua+gyxeMS/SRTpJx9Zk4aydLy7t4wxcrs02LHZQrEg8I8JYccdDOhnHRdp8Mpl5mVEwczGYfGxb5FhsfhQfYczDlVQti5SvnhLVdybXSgp+I/dH6Rd+vdWm/DeZeZdCkyiYvhcfUzD4OPsuPtUTZ3G/5VCuxUpLF0+XcfBN8VV8LYd2Hcv3LHpIidGP8A7X1fXY99lhpjLsv81hvmPjvGGxfYrPGxYqZTKhVBxxy4iJf7XFRJ075z+h4krL54R74U6af2+0zfNofqfQuvh6jfUvjmKIMhlTG/yLj8ik9lkxdCg4/yL7LwmYrFoMqmTn7FIIS3DYYbB0M6GYcpMuJSVF8jT1wl3+WEtPQXoy6Swr0ZskfZ5iotI4IlgjSc/ihpNO5SJN6KmqSLzJz+/M7u7D1cqlN+Lbe/C/yaD/Iom0kcKzirOFaMrT51edjoxIqKllp8m5fCkPSXuSfkVgjTxgVE8hvPacYbCGu9NUXFIrT549LtMkP/AMm7wudJM10XtXkpHElIuhFS6LJfrfCUrzmb17/uo0icXvsMU2LbHxDjj7T/ADa4LDlinOvbT1h8j4oUi8UbwunA/wCJf7Y/pF66nxwxeaapNMHw+GFdCyeK+kzOicPc/MX9vuPGv93oiGWfisUXmsiiIid2NYYYvFJmWX9MSpynLkUX8ROKL/8AU+GNF/qSXlMqiy3p8Scm4yHPfD6EK7ooV54/iJeXSTxhrzbHjP75pxIl7VETxVZCpKkSK/g/2m/dsT2X06w4+DpqPi0sKU77nQjX47Kva7vFPu+NYYV4fVynSRf5V9ZjdJd8XxL6bTfJrDJf4oaL6LxmKsH/ACJpHpfhoXGGIV3w/wC04L5YxwrZV0tqkhihJWiRNe7ihB4S9MXwYvjP/aYSPtRhuOxTBk+9xTa3/PccSCPN2Yv4u5f5u+/mPIt1KcpRb0+6ndvthFD/AAr0uC+i/wDZMUitHDL+6GnlLCa8Be5fMiTtQf8Ajmn9Tcp7NvDC+H3MrqfalSxfG4yG7Ci13bboPt7zKgyDIW2PA72X77+qz1T6k4Fl3K3BXTmQ9NOj0pwVardy/FI+7YRQ9p4f6k9W4klwmnsRRqtY5T3fCkk0TH0X5W/GpZUw70K7NT3kmpb+1PqvyajfInCqov3qSjku5U+5eRTCadS7itT7v/vFfxIM3bh/i/mT+bfv89jcWw9tiuFC5YdOZWaiui4bi23YfBpjImG4vsMN8no3/wC3umxSvUk4+3nsdOHLG6fwx+ivrsPhT5m7BtvxwY9SqjTKQp1FEjqjdL19SioqCrDSVupTTj6nHYigW6PuWy8FFRXRVRfFH6tI9GKov34F9dtupfCqp4Kb/u8hEks9U6lPZ/F/q6X7kRfr1q5Rju+TVfkSUuMhbYS/lyLT3enVvxFsq08Eonl+qTLmZU8FUzKvjXzqVhTgsvUqvRXvRfNJ8zMnFZeZmh1QoqL4LP5lYodSnSi4STnXkSyw/wAKX8VF6z3bLYVkbyidSub02fbYddR8KWM8f7ovUzx/uUzx/uUzx/vi9TPF+6IefXHIeOxRNT0weR69Yqbz1G9Md2DIOOOuo/PZ7k6/UbGnVbbVxjKX1h/38nNpbr+79CfT5Mp8OvSx3r+k0fy/QJ/Pr1tzv/8AYDfKuS2fr1xv0qi6lV0+/oOvri8/0WezU+nW86k1iVfIX9Bfaubkw8kx+6ddrpiuNNjyw9ju6zXY+5k126Dj7Pf5YN1NJPt79inU76jfI+5/onRidL7U16/UprfGdP0KcXwp/kvDZp1qibG8oksKkpYNq+G7w+Q/XUOCdYbzGTQsVXgU2KYVqUTl8mv6t2hhiQyG8bZaZ9LC4Ig8++3V+XDqD9Zlj9yEL4fwm/DdhZIk4Iqep9yw9fQrohRP1X//xAAoEAACAQIFAwUBAQEAAAAAAAAAARExQSFRYXGBEJGhscHR4fDxIDD/2gAIAQEAAT8hgqlxC9ELUNJ+ESMO59ibncyXgWox6scF8Ibp2j5EbuH5MlXeXj8nsWiamN4Q5fVB327h8tYzDhT7mafdeoILvv8ATGducDyjcXuJvxw9mJ9fKGaLsGijey9h9G+WfQe8NmT2YyzNxe5nj2d7n2wJe6xvqt2PRWz+Bt/r1KtC2ImnuZ9EfBEFmyXd/AzR9n92ahzHsUjgYWuekvkb/jHvVPwSWUJ8hZ57DVn1TrwI1UMpAV0vh7mrPNt6YDVT3CJh2fAQs+7DsDkcrRSUjkWBp9tDbl2+A16AKXd2PVV9zSw0zYWp5Bb95iM+V64k3cM6CdCW7RKVviRuaAEKW3CAK5AX8wSfgjalpeTX1lifogv4n3F/q9kagbfgwHbOyG/QDOtcGZ6NyxRcfA1P8zZHJuw1fcfkuX4SLRbaNTyFijHqhHI0R/Iz5N9j5ionkCzndv5LiJOhPb3GXW30Ism8IyxbuRsqXaPlGbHLMr7Jr2Gardbm9bk9k5ZGWwaqQal2F2JIyZWmBdNRqP4ExlGG8j7oMribZmD4F3wYGAgqr9/gfB7+RCv7B3W3bSEn+tlqRqK6N5s17FE8k/gSqJt0PMPX6Hzn5DVUXBlZHMncuH3MW9xh5FeAkYKl58iuteQuH+am9eshujyxWwCF3jAeU3waHmRLqbBHpB8D6RDd2vkupbpL3Gu5yvkvB7izTuPvTFYUFmS0UvVlEuAh7AnoLRufijyOKxd7esI+Qvk1PHxMjkQW/D7JdfjboPywEXkbXMlQR49zLzyZsE2RbsYrVwG5fnQa0Lux+aT/AGZr50O1D3Gfxv4PlN+4n9fcUpzz2GqruLMrcavcaorZR6ozJsvyTcFcY9RTPy/QJlZ3MK+o7DNZcBqrnEvlev3G3LkmKU7HwXr2b5F/w8pk9rYk23z4Q3ftR8GQyerFbY6Rty2hnAX1j+RF2C0blkOub2kqpeR17byZp2SPnDE02ns/kYqxkEC0rul8E4tGaIuEdhv/AA9R31EB36fgzuMIXxmeN4HWQ2Fe7ET1exXQw3PsMvcDPdyfwVR2U5+D7Hofj5R/Gl8itWr0Ij+D7KGD81G6eZDFl3DJpwYqo6nJwZhd59xGQ3CK75Y5kyjaGXPAYm0ebN5v8gleTeXoNFfMXS92LqbS9WWk92vsJTxTuEWdbP5k0uIMUTu/iBPu+42/Y5M1ufmJPRoZNX3MN/IXl7ipO3Gqp4DaR2QneZbGxCqff6GryD+hOteonrB+6Pk/vr4FoykOnoJ2d2/kuT8stTeDSN2XKd2MUl0k/WjJ3uWYO4flBq7iFUE6SIbmmHsPWWsieccjfuwQVdwhMUNkvZErdiYtLzBpq8VfyP6JZm7DdY+Bmux4DTStvs/nr5HWN+aMyz7fI/i/AVqmz9xjtORS13E6d8lreUK9jEHU9jTtaf0sY5LiOMWJL+Arxqa9zE/ZfYtvEEPJu5GOnbJkz7jSnqkizcH9H1hdJuPkWCjcjQjd/ZlXaB3mkFQfq65CZR+0e5kI938Df1js2/cD1a+UIVw7BLrL+uURDqV7Je5eU0j2EmLh6sqycMtDYvi6LIQ/DwZy2hedbyI/pjviC/KYzfwDdx71g5d5gbv8fkTL9khtn0jRqSMQWQ/JDR2lEOT3f0ZJthHNyIsvOJYvLFcDXRe3wD79oL5sed6jNLsOujHohjBi82lz7g0XZnRhHhn1WB9nj7j7SkslxQe5RX9P+hS/x9y8PMarPuIVHjKBbPyhz3WgVNKXYVvbr8megkDtd2PQWvQsa+agb+wf2iE6fL+hfy/gvuslYQ7VvcLZ/DIvmgy/Jsvla5M4r4P3ipi3ZkiZIvRvcaWst1I8hNliOqsgYyMzfYjdTwS+CxguvgJWfIjTgDty4LZeRzorgbdt4HfRbiSqgXnmNcPuX2P+xPVsWwd5JLyXZ8QKjXoEWrtQS6o7mRrlpH2NhJSG2HrJmhXjR9UzNXtIN1rsfIC+B2EcsL4BNl7fuildwZLQthVj96Go52ewl0cdemTIly8fIs/YyCciCxHVwV1eyLOA37jH9RiX2D/zF7W8hekdkhrRyEoULEUDtC6ndQKrutJbP0Qi2SW7kYq+hlIds0XZ9xPRvwMdGu30I/aHpEWvcbm/QJn2Isa8s0wy44J6EuUaEc0cH7jPVTwMdTksM+5SORT4Uoms4EiSnYhVk3I0yOB1XYMK7kQfWeMEFw9NrgjXuRWpbYkob9pasiuj1CJdd5H/ABDVPKHKYbCsu81l6MR1ITZcjXT42n2GM+FHSN2aDyOVnwKibTygS5UYrLpJ8It5b/YZUdo1O0o0Ov2NVWy23jY2UVwMun56DVOxs/oRsq33MmrjsoNIyZ6YuHxDtP03HXNwI08oSavgh5HeZZ5FpwCrqOIFcbMovUp3cgksj9ngWojYbobKdiGPk18nzpC87h6fJn3bAswul6iMgzjllgQywyz8Ibs/KKYHfd7MDCwnXuEufwWjTZsvJLUZRyTKttPdQjowMUmC1dxfEvm7DRRh3mFeL1FIlcn9QWsUqXci4Tyhzq+0N059RBbsNboxi5EVYEKwrIxj8ew08HsYyjFoj9ZLJe0eweT7i8nIU91yOm/G4hUXZFaKaoarmwVrxJHv39SxxskNZDa7Njtc5Hne7+hnk2bFmFq6IZ6LeBP2iewhoMqH2CqRW0F8TGeq2xZZ8ygZvq39nyakL5g2eEKTQq3k5HWS5bGvn+iiMt2P6Ma6cgf9hrws8i7PvQWUNmFVaf8AMZbvJGKhY3WP4KVr4Z6wpFk3yFUtyxhq/DM9vCWi9Rxbo7wN6GMw7Crm0tWJ7t5Hhe4H/kKew8RPt6/csX2QOdE+RmXSC1+6EvoS6EiptJFZuzStkZJIR0QthR4L0IniiX7JCzuX3Jbk9X7xLlWkitW39LFvsyP5ci1RCjv2/gx1gwhTwZNXvkek1YtIFhS1LIyoSaGLzSdxIovcWr6ysNHf8SX5HLFrCDklbQngFWkzcst0d4/w8CRqUOy9xWiNkh4TU9T8yNdfUTrN8jXTAbwZq3eBbHcZ6nw/QZpM4jUh9ofAteGuPqXKndEgtPkbNhPiT80ada4kbx6jTMEKI4kU9FwE69vH1Gqpwl0HINOpHCGaz7Eiq0NN3cvm+w11kb5MmsayN9G3vJUi+jk2vBBTAgrwIvVJloNd2EMEr6jEwoyJ/pyX0wnW8oToiKwbqgp9hk3yx3CHqWhNkzM3At+vctvxyZB2guR9wKVRCwEN0iNJ+XqzITTD0F13yN25bLiH6eTJOJIMImz3qJ7xXf8AfSJIrG7gaPhLJv6CsH2Gv8vQbfRQl9mBRqg+BusNpmmGVDcVtX2Zl29kQVIEbnQjIXceYbJqi1ZPl8DFjcPOHIaqt0RoPSBKuz3Ht4YhdyLUKVHP6rQ40PWC0w2EubLnAa7oZJQbskpNMmtI5M29kWDubLaRK4M31GVh3+SwT0y5/IkwfYhjGC3EPgZFTxIZe5eDQvJaR2EiFDYvYV5vc2MqaXPyOXfcZUvJao07dFLSc49hU2G3wDmLi2PYbZvTI/hv2NOKNDCvxgkwGVa2ZnduC8smfqMkvcZpLp7mOXr9sSfKLNeo9QIH70ySPYd3vC474XUfkToB+RvkjprRJ6IoDNw9DbG/BZmmPdjWlN7gnuE0IsUKP2Bamwk/garswNr8DEqWLbwx5kP6qQ7EOT5CJ1WG5ODPCrJyxOro4UaP+IZu2IbLJ/YgZfaE3ozaTMPkyqLz0mc7D1R+R6/Y1mNtTKwLmOwzd0jPyLJfI9dcshUcAzQkqnc/SiOxcoWrPYsJFv3fYccuJE+j4DTJrIqbLyRdrUylpJOhUOKuMlgIzuTWuTQNy9fYszZpN3MmpAxeRZmErNu2Nfcx6iOx/DFy/Qcycl4nY4hK+yRTOLI92YqIizjg/kPyMa/kZLd7jbZ2M9G5klO/Jcli10SkuGIV0WQbo2KVRuy7xaCK0syfB0h+aWapswMldiIrPQO7LZCdJbiHath7GY7iuY0LFkXwN0B7Lgh1YtmhXH4GsEl7s3MR6dEk3TkUoIvBvQsBe3oBSUrwI1uGbc/grDbYF4EKshpRQ8GJYdaewnvCRGom7DTWR7MjzDrEy4PsHoGvRJabIbmGCWYQXbcyWBPWBsy7Cf5To2CfksB/tzJ+MS7T7YC3hEvOBFZfZDXUNMlzUXquIEUyzDfQhyG5pciuL5GSmPA3zjZjS6TuzYOPcis+6gyFIzKnhEVSHZMyT7GSZP7M0gq8vZGdXgsp5GmngXsi2D0sF7nqkHqw0gQ1aVkJZx2X6BpWKOxOxbuZoHW7mG/4ZnThCtE+6FeQuHoOWfcXwi3Jykb+IvgbKnyhJkjRCvzeCFgloIbshbNsaqMK5mh4G3E3npUwqrEWuLFWQQGhlkZkk/2LfymEGengWqIsF4DVYbDczMNMepkv6SGrPUYr2MQuYXi4MAcNRWtw4ZmORYQLdmKOPlUioo2/YSaMhToOGQveTK2ix7lUwFKr7KWRt3Y7BKluEtxtdHlLdibfeDLxLL0Of7gWqzNxbSSfiGRimbExJs3sy0GKQZ7wNXSCkdalx6mokZzAauLMEUixkeDJiZWjWCV1dmIYw/hDTAnqEumBSEY8qJVYJMHxVFs2QY64GGjXcX6fSEdmOWZvNxN/fFmjzT+hVDIeVl3LKS7kR1IVLj3EaDRZF1Zvcu/MzNbQHKA0sH5JXkPoCyUieZqhyp5xLemw/nIYqi4IyfA+gfBL5kFZhZLu/gdVsIMTGrnQsO4a5+S09BrYuOwM5dhz+ZCFYCmCl7YGdvcJHaMgMsS4Mu26JpfQYMoTT+j2r6Yrck6KOEY0wrG3yRsEvcVB00Yh5k1FucEaq7QOu5JWVRwIrBL2LIuwnU9jJ229zKiq8Mncl4Y2KQza9O5UXsTfETV7Q3YR4IbkKpgtGZ0hCkuPocqPqRLeOTAxcj14NRMT6RuSgiN0+4aMoEvzGOyRpoSq1fcWt6ESeCJbJeozi/YsBNyqp+CvOFoY02kyzYs0If1hCk8mNcZg+fsdt+4pfIbHLmafcbdGKz4LMHbkS7jVZN2QVIewmzXhC5YNrPGBSfliQja141E1gTWL9irPiEhs4qf3I5PPt7GJW6Mh4kSd3MLeESchQMsTuEPy2kb5TPEKU1fCJJo62tiPZn0O49CsVjbFmRkMyyEuvgK8J6L4EqY9ylWA7R8/0u47itE6i8kLDmsHBqm6RdvsCPpn3BCVkG5msPKcLoydVW7EbXktlfgU6AxBamMykzlBDcWsyHN8Dde4lXHrAlp3TG2RwJ3q1oWcBard2YqsxAcp6il8mIsg6w3+wxQypHxw9S2l8DlVEskXA7iPktcDrtvZFNDq1LKgwgK3Y8Isp6YsT29iLMZlLlDv2ZZUHr4Fc4dvcxMFmc4vA3ZJrme7HVVxeDedK2SzgUqSor3erzZcEq/7wXRpJDDsSWGYnZllid0hIcK4SrHrhmajnH6Kin+aCuMlpjXhj1YOG/YjVO3yN1O4rRxoYqsRY74jgx4T3QfIQu6CNZftDITrHyWMOCyDTyDPz6RlDLlid3Is5Czx9yJqNCmorIEjRjb8zZW4lal5whQHLwaaMsIchLxYrITrQesmJWRTKlshOxkMZL16FLHLFkiiK7GmI6yjFGo0NfHUfo0aRVMOROrskuxvqPbHxkPd+40TcYq+hIsjeUdvLZBLGctfoiKYaVSwadpcPcn00XvZCwboweWbeqd+oYRRiPBYL7cbuAzOCURSi+2TMMFabeHPYlk8isWGGXsY6cHGX5GQMaxeUjt06GaDKjIWnYQ8aCF8NP0me33FmhJNTVmSY0so3GPIvGZ0wNQbq4k3fArR3uNUZGoQpV2ZKYzWWaAil+Ukro0CUluu5DYbzNaS3ZFUxaUGL5CboI1QnNrjoWgGqy4HdzWwirC3Te8lhBAxLqLBoiSiRWoVBK3UlgNhSjTtIt08S6ntUyJ8Emnih6K7hT2MHz6Ye38L2jfYW7fQkhMbogW+qlRMFVJhzimjGFdRpYuewj8TA8TjtbNmCmW0GGbJeWYImtk/eWSuFte/4JrUgQoucXi2044i6xTcNFwmu/yUptCOjIuhqyDAmP2EMyRjqKli9C2GL9iNpQTujXczELWL2UZ/sL/3C+BVPJHMg3eTQT6E3JLbptcgw/V0ZYN19EbX7U3n6E7YDewxd8fRdz3KAL5N7kKkLRDbmOydxSqrdlwr2oO+NJP0Gmm/hfJ+OELVFvL+C3otEExEqCMRVkZ/wI+aGcYi4T+3NQ2RExbuvCNY4fwLSEYecutfip7Bs0vV6lEWp3HO6IdOdxK6YWGofOffzqo1zGrNiDaJZ3hIpgaipd8CY5F4pTvjkTT8+e4m227LHanCEw0qwxyyCtqJSuWCd7vkdKy0uQRKU2TLwblckieH3E9LMy2IarTEYwbT+7DlJn9U1kSsSwjeanuMut1OZEGDbeiGyhJiZHvGSZtVqJ3GUShDe5C5QH2JvATvI6shuTH+EMkXGJpn5HYTj2FpTJKrsLWxHYwRAe/D0ksUMUOEkhCJiGuqWVLR6p2alMeoo4Hc41w6NsN1aS3GFMz/AAabGKiD1VYamPDshz9pMhoufcjRCmp5OIL2QnaaBtoO/Ih1cCL0TLZoHF6C7suUPGURqc8TRLu4S1KV+vPR3Ak6Qac+HyYRX94EIjDGVjjKpjmLa+MWnLbjak4a+kakjoZt4RI3JG+KMF4nnRyywsu4cd4OYa5RhFIoJFCSNGH5mSQlqZvslgKbgTW2LQwXhffC23B+46U2jN4ImzQa0dzwpgIEdRfY6WMlWHNhgZWbKtegmw9H0NtE0xqL1x5Gth2ZjVLg07ccaoXpPYV1GrLhDnTAR84EM/Y0yL4WohmcS3cIiovcmVYpaE5WthRrDDCVAFapU3PUIhTak8zDaDtHe4Y4PWPyuZLkXHBKfYR+5Km1nKO+C8wPVX7LSwuRDv1T0M7hT3YqWblEpzxi7jbCfNZ5+xCUjISQuyhDc/AoXZdeutu9fI0nH0LyKEliGcLtD1IHCN8/Y7Eth1vBzmcNgsjz9mlfYKfFSvDSW7H57k4KqYYYJI/imyw9vPRDNPpTwT5Ex7ICMjbL0weBZhiehZlJSWqUjMupCDhtosTeN1ChmvgXjL9YlMzgZSLriuPGhDLyywSEl/gnW5c+jEJL+Gjn2Nb08ycnp3HsaWPcbXPz0ENaiaW0wJ7c0YycMfUxmCx0xWzknXFLseqOX9Ed8BFGHSTCaeBRqL07GdAwhegh2dyOXg153GZO6Cla9sRRtOpoMVkTN1HjPX2Jc0fBRp2exHUlMtHw9ZbSl6UnIPNJ/Go/guTobwSCCfkJtgr2Xz0EG2P+qQThjbEyBJXNr0+TR8i3Cx+sSkhAzHBnd3Cl2hAxDjCSQvCOuWGJpSNYObaPLk0jRo2xlCp7OI0qHQvAS4Nrbti/I3IhTuGsMC0IQS7emB4rQUEkvpx93Y0BYt2Ldr3FJvF4ZJR+5HFMozmnfAdJSoZU9hta6Me7QhstJad9Smws+KEJLGnZt4Ne0GCZct4YrJ4RC8ZNXw8ZClhR2d1gPFhiNWm31iNWcapx5IXimVjhgJOkPZjWoxMHiPuF+7CuDZsUWLiBF7iTJ8/Jpu5Cbn6DtBs6CcbkxqqMVJJu7ew3JkshqpDRSMdhO8X5oJVUsmb0w8mKWRlqu+p5hsY2htS/eg7VfB/JPRDbtnn4++nD/U6LOaBH6ELp4EiSMCxi91TY+IHsOMWC1ZbPR+avOFdy0Im7ymNj8Mwu/gcwpu3IT1l+oYJS7DPV/syKXp6JK8pkQusyMbjmLzEWyRinpGfwJuKPdsxlLZOHJXV08GnsxMUW6f2K1CM8cfHexiX3Vu45qJ5aQxqIerDtiQsNtvJqXcjJjlGC3zfga5cF8Cdi3Knkkqp3Skx8thCrlr9i2mB6KJHPFOSV8ZFXsxbUwXMk1Jfj4ng/WFV3+2EuBIljwVZj52Fu0KZhCJWSHauFoNd2NxRv2E2chf4+DLbwKVz0Q2yTZY9xu1X3HvLuMzwJ6awbSnk0JDeC4M3V+GOXbpuLt+sRVwGJhGOmR9F+mv8AArrEtNEmntPZ6mIke/5NhpNrIBi6ghglSjAwbWPJZ7bsvVeU+hHkQx3ahtCZ+UD1KGmnDTwhqs6ohuPc3FqGmpbdTOGjJVDmRSlwNJtvAiZdWJn5MjCe3OgqBp5ObvMPwZkx+0Mbpvmfc0X2g/TI4TMEaMXCVPsLMf79UZxknCs61HrSrTguyn2H/Ve7FqSmVjabrUelMi8Nb6Clv4sMxJ5mwrFHGwY71Dkazex9ZGLFOEG75Ql4YOSeeexyH0LbIa6ueg3zSW5Bds/BiWPcPosFoQpSPgMZYYsJx8HkJKCuqRk1RNyelyYYCXk1OLbgSRq99mReTRgJGN9iD/OhekwmIIYgXUM0+rFaZrgU8ESOzUp9yZrXH3cz6jCX7cYeo4MUqi6V2N1ZDGOQM2yTJwRVfG5JZuB/zU+wy6YU81o4x9yeFhbpjsLB/H7uOi7jtK3JNGwnjylmFjtKT+O5JoO3p8CiHIlNcRiTC/bkas3qTqiZzMZrIbOEjjvsZ/r+xEsMMWh0uO79BrTdVYzVJ4G8si6hGaN4E7oBm+w9TsE87c9HnjziVB7sMZnPuaToZodvL1E0Yce4nbUTiP6LrzZrmFypmBDZg+E537jEnA8/f+FKMIN0F0iYn1kkVeq3+6ER5EN0n+NChbCdE5EnbhLcWwWmTooaqQ1TxZn/ACIZDOSLugTO/kwVgQMfAuu0k/79AkJvZvP0GzkjRnhjcaRHuNI59yJRaqPiBaLXza9SyVDVbxghpMKKNcTqO0RjhXbUTG80xrxHuQPLmCN4YrEnk7ob4xNKumsQalvP8FvGO74FKC0RRGGSPI1/IG38GjMybM9i2GySXJDDcMWY4Qn0XlmqqqO6eZ5wE40f5iJ1kBYONJMBqVfqgjY1Qh4MPdidv36w3QuoSE+oJi6PoSo5boWeT3RE1ni6kGAhSuXivYW6lXKTyWTIThpoayQ2f0WCajm6HM0xu82TD0Y/6SBYYe4wnyNofbHgRJ3TV7UJCXm+wspFkTLoJsbHnRPPRmGYvwbMWJ8qm80DvfjgiiTUYqj9kPzW1BEVbdMLDV2JnIjIyAx2XSMI3Ha9Ex9+xgO0Z1V5foh+UpqYwTWL3HmxJJug6ba4TIk91R8r5MVisMNtRK7D0vrYwAHr5MVTdpEv+EcYhAkR110JC6K45Ch/hsFJ+RXy2EVbg1Q1sJSV0klCB1GLibf45O7mY5XEiXhReWRwJIk6x3kbbwMWLMooKcLOBYbzvh2EnMTTwIThtI0/MkbXcr9DNSeDJr8tx64TZR0GlwwxLJD2RKGffI16ibDBiGsl+0Eym2GL1SJGGDWExX9Hlj0Jsl7inKeAsrAcrVVScRgabTlJN3VhW9KMhjaXy85lqJsJmpIYwupLoT/4TNBdBSTnBLFuySzIJcocZd5S5/w/+BgmHqCDUbBLEQoGu9MBkaxaHIcucO4k27CT1w0E+GBRuNeTXca6q1s7GJRiUfpRLg4x29bGXT9UsPBi1kgk36GWM0TEqvYbIYSG2fVEXk6FCbwTan+bjZxcug+hYLVSBHoMWCpsiTwPF1URPYklCgsmk/LxjSwmuwQ9GicJHJvVJOGi5O54P3C1JlekE8BbThxmM1glaoTE7d+8J5TzEoTxcwem0zQtXXdVst2L6SC6klLHDfBFJHBvssRWlunlx7GFsoZWXheWmC0ZimFEs7dF9Yp0IsRr/wAIfjLoRXfq44z6/eJ8x3mYtSGjjhG596kyh4pn89Koa/Mgt4Gu4cK1yF3IsrmbcI8i1QS/X6WIx26RGIK4JdhFkZgl1JD30sLUg4tdohe/oKnDsQzK+zKfFyfe5+/6a/H5iJ9W0jfpE1Ja5EvkCznDvxj5IUS3FFYkJtDxSm0081ENPYm/m/LngH4fkbwf6dTA70skUjy8YPNRv2vVme+h73eivj/MSYjZII0Fun+cCgUKGUxiKRoygjoRQ0Z5oIXCGjEa0mk50fz0Vr6a1HcU6EtBOnETHkaHfbfkJ99jNwHRKdxmi2FmE9J0YyUzAyXRnGDhCqWRO7Y9FJ0IhlON6DajY5iO8cvdCbTwfEnHNO40lpD57lV9hu8lsiZETGvxJZRwl/uDRPj4Pqr+R6DZKPJqfT0Pt72EzP5fJEVGRi3nVn5qaIxKjGom9JYtYrVktiDoPjl0GzFf6DxXRLth0J7/AOT/AKocRhYttLwLkaAzPrq/2An9HRNdPTR0fBmOBj2Jjh0WrIbkSH7DGTCENpUI/gTGo7qDVRn4Ixl7Pse3x+Yt4eqHTg01l8CKUarpuIWLeHdvggdN1/WgjM+wm4OrVesYEaWm0m9GJjhQtXiL/wAFQdp/IRh26SzwwO1WhtfJqkB5RoyuhlsPrGHoNtTYxOxwmH5DYhkCfoQxQ8pg1+BTH61mRagkokE1NjLmeMkbkl4NQ+OhL0c4UhJomwMsbHoOewkznoR9N9HsD6kNF2w+2x91+zJP35kfA2SEsOXCRdTeUCFhp5qU32qOEnTeg6TIMcJyr6bGk+5SmiMUwh5PPOLGL/N1tEPOhh6Oggw3qcyEIV56XD0FiIljJVWBkvHU/FieILN/1R81w8oczbFbYinT4GNER8Nwc7j+mhleBn/RSVJebp8k+OC2Ibmml0n/AIFYI5B9KihWfr3P79Bji3FRWWTEM6EFPjoxdhJFUr0Ymg91oRyhPwz3Jsaz1NCU2Qpq/XJxY/8AEyROXTTDiZPNiJRJ0p10P5DKVEgSTNBJdBXdmOFCGpsSjGXvAc/pSP8Acj1sNzeGLoNJ7C+m5FiEjKw6DL6LYn2LF6CHlOZBIk6x9efuegnQZR0XmAuEWoC2pqHcCRL0FLkfoaEJ0xOYf8a+n2mQhpgJDXAkcDBO90I/qjxZkVnP7IaWQ7pKFkrtL89GgSqy6ed/BLQiGU6sVRhXt0G0E3dtj6D6NyQ8TdbXiaBoyVenj6SjbwK3Zz1DDdSjC0xeVeqJCZxnguCEkhO8WX2bWYp0p6ExrcZ3IG4x1NT+0HiLVCMhJCzEckSKE2xjVI6ecQyIf/noxkfQ0EHU7RbcKGxG4GV1PCp0GZ2/YcCY6GGeC/8AgmbDfegtVjr7LpfQm7mJmNGEQkSsIMbp7hxnAaXTaQpIQg1ttDnXK7Jn7Hq4Da4HZNrFtE8ihPzkh1JKDZYZ0qKc9BTFhqSUaGF+8dBFvFR9C2G9GF9DiYtPQRljOI5BkeolsEltfyYBY30o1w7iNJf7UTVGNM/24nguCErjO6/YDXsNjhzchhik2KYstCOsPJPcyUMeJh1xy+egg2kT9QiojLGDijPMTLggv8dW6SOcG5jo0hO2OHZkV7ufYljjySuxxzdrItLkkcLkidP6uZ5jDBd2Jk12w5YrfVCjnGxV0EIW6TphEmL6L4voRfRXTx1H3wFR8imYWopGbHKWaF2E5LZuD2w/0LyJW3OPgYisqUG82yHbq7EWr8D3HfL7DbctkWueo22Ne/ke/sQli10ZCxodE4TeXSkPv0Z79B9Cl0JC6tG4fBfZZiphaxfevRudzGbWBBF34FzcN7tZkFXx+kqvzitiDlThdHjgnR50Gt2939iFqHLYcl+Z/cdQ8VrVCL9N9sRokEE0LMF0oEiGN8Zj7fPqO2Y3oktB7+RkfCxPs3iOfCFqYMXXu2iVvQWZMRRZEDG+adNMpzEWTWtvIkir/X+hA4ZD/FtikO5og1cx5PqqUsG3MPl+DGfg379e8f40ulh0I6aToSbmseXEW5V3hOSdfAk6Fs06t83fV4WbTX2MIWFFyxqSuZUD4u5TD3+iYqFe/YRn0WX0iHEb/YdZfQQkpzx4SS9WLLT80MwfLw7fAsxRU5JSnHyavC/ehTMBzEZ+q9kIcYXq+BLxSmM6cksGvP5krenZdHXMjyOY4n0J1v8Af64i0H0r/wAol/k9Bf4QSZGOYtUuB40RMktJVO+TJbpb4DJzWfQXDyTtI7w9Gp4EzhIt3c7PPx/wQlg9CCdLdVA4jDCas3q4+DA8MfPpTYtKJ1Sr8kBa00GzPMGb9/Jkqf3cUEulH7Ayl5trCpnFvOv0S1MTFgs3iRNGM4N6DXnyME+nfoTjV8jDRkjsaKE9uEhOY5vpJ9OLoT/wQoaLdFlryHPrGmT1LCW6KM3ShSbeh4+sW7Ice32bPD+CIihm6ImE3G8V1qPjiNsNUxdbk7RsQaENKUXFTUZnI7dD6WGhofFsMa0QhOs7GHQ7N+hdYGLBGr+zZjDltPkasIu0s+eeLJnMmSolzcuO3uavAipF5PZeRChPvBaSS6PeourpqEESJWpoJGg9TU7DH0kupgJ6KCdKKCSHST6ywYDlRxtg+/QwIzUfBCN9JIsRZvNikQrDd8El0pPMPdh2nqQkYjoydCfGnYgw4n6EufgycPVjxeCRdFLoiOZaej/omqby/dxlPeCzom4ucWyZ8YFtbVdftkZvPHpmKamOW39SKn6Jtz1+SauvUkscOxGdDOw8CZiBCsnuYmFOsQ4E8aeRqGlMksv1BiR4dDW09NEnTQfUdBnGDosYn9R00H/hkxhMT0Mj+lnohoINBwi6nqCCkh9dkQYYazuPpSIF0WMh2H9xVoftBrAlwpfuQSnI73X7JEEkrFrTQmN8EqJdpKaITpDoYldaCU4nBKXvkL9cBKaU3DIk42HARxgpr36ISeLztrsLTKhhCrYpehHPR00yTsPby2hehTR7jchpoibLpLzErkl2YdGELV+Bj06UIc4ltwkkuYSiU0Ssh/7oEG6v4lAxGpPQev26b/wDD6phIMVf8Bhok4rT98mAmstWPW1NYcehA48klkoQurU9hQalxxj4JsE25wpCd8XsPOV2NV5fqkDJ8T3K/efQxSSb5zVa/kQ2j95E02niwcYSlZ3e1DCmXhYW1kzfJW9xKdnpi3Yx9dJn0OJZvHhj3aI+JuNGd5l+URVFq4E3l9hX7Eh/MBNKrPLctPBON8k7MLfrT6Sw/qiC6CLD6u+jdJBFCUmPFkOlND7Em42MXojPn0EKM7RTm/Yw1Fb5Kke8mYl3hYLyYY/htyNLFYED6H0mF0v/2gAMAwEAAgADAAAAEItaeREh2NCYMHMj0b7NYt6zVNTN3onUrNzFsjZ1yGLDg/jPSeoa3hiqf35+KPT/AG3RxXm2ChFnRUnuBwYB2B2f4cjvgwSrgNceMKLvbyg0SSh2lFr5mMkNj7UC/Xbz9ogxL4OmnZ33WsdvhZ37ZVXOEv5A66kVWSHhoGllK98e4eFsZwK6ryongKAvhejKCcpRDfDzsDJAv0Adu7bJ+5FsjxNiDlSUWd1Aacuo3b2tc7A/t3C4tzoufQAnI2kvh5Yw5OCIOmz17Uuwb3bOGxJl1rZTBO95XPY6LKJPvIKC0PKA6+po8pPF/wCiqN+068yrkKFnERPQbI0DlFWS6wPkX/8AeExCXxKgGPVpTLNSmrPYwoktb5u3j7+ZzBbJqbtGeJ2E6GbHXdawdXlMfKosglq+lSd0fnMIq36qCog+nQFNMyZCNautAzvn8qM4jmnauTC0nI+Vf5/BYiz5PGRGsOREen/54a1/cRsYgCNNBjeJm+DF4ovrUBDvIK5SrwMxaCglw6MAku5OvhEUNrS1wY7AJBTPAV16FNyT5NlSWl2E+SZ8jalX7Kz5z8DfW/XdFRx/1vrr8GNXm8RVaRyzqraUskiJ8DbV8hVHtudMPjboLahmuyC/JQSyz2vlco2J9gRF1OKGxHnmtLVZAMWkPB67sDu2kKo6i2pKayLi7I93nVU3wBe/9tqQshw4qJM7ThiBBRovezXIzCQiqvVj0dUbbK1DgI09POvOHod3VAgtYxSphWvXLa06IYP/AJTKJKf/AE0jfX2U/LqnPFoWxZFXr4RRdz+jRMkklcACLQLdDMqLn1b/AOtTi7FvTJzImAJlfEd2KosLAuhfKi0f5O0R3nYZMNJ+a0gMthW10E26coeKVSRC1ZyWpyCncyA8zrUA8yMzqwnEV/hdRE/ZECfHdOJuEbUrQEANkvVhfXEyNJhHYkWnC9wcw3OBZb4QUIRL2gGNXOvQhRtnlWu99QuOhSRakCyfuvoEJliZGylwoBY/xLMo1B+s3pIGsu2YO0CeNxEYwmdLTshYG6AB2DsKHQk6lQ5gc88ULsXunx3peJnfBKTmbW1zVRxwFjlo+FPClA+5NpEwRaO3/TQhUzASKB3csOgo8Ip9jkMYYVntAunHkIrlGCap+5YIyDOZJWaiElawGOvl3/R3i+TCUxDkYbbp1s5xG6A5cs3YfN3ld3ezlKqK9pJty8ush2zCWOMEApSXts/+hMoDAoa70kYoo6mG+dq6KQLLDy2P4Ai38fMcqdNfXdO0JXnJaFx9RUV7tn5kGkyUdmGTkxHldtL3kh1UYZQSfIjhoyTlzs1T7yFKsicP6n55GHKPsXftgEDzuHmTvnccxw3YsYJuLH+zlKA4NSOwgp54DPkmb+EROU9P3rsQe9fqLgntybTuW9gtY/OUPbelbczHeydEqyqeYDOqFYyzw4VMrGRHmZ2NvmzB3pwpsKQJb7vyx7Dc6Sp+nfZmpOQAc92WLcRv6KbPLavFSINsB7YfScaN8L6pR3coIlTvoMT9t6CwQF3DOrCVQm6W5LwSe29XPGFaCRLBxNNC9znW8sZLMeOP0CmPiPkUDyL7TMllni/Xy09VvbrnU7c+oXmDLMGFGU/454oqlvJoSv3MB/mgRqzxCj+x38s5R1EUV02KJ+0EsIiFwoAY+/8AKSuLRTA6XcL4rd/j5JNu2RS/sOY8N0gsoJn3s781UgL3sgYe/wDpxbiQXUaDQ8k9zzE7tRdbVWD9zOXtOqvAk6s9/kSJu7uHEPcuIFSPw7HgT5WHcVVkGJsrIX/GfuXe+pN1MP6uQcA7/S8e86utVZuX7u0wQjR4DGnyRttVFXSm2UoLD8qLw51rnDx6ZjKYQX4TVk3OGBuIk6QC0wi//8QAIhEBAQEAAwEBAQEBAQEBAQAAAQARECExQVFhIHGBsZGh/9oACAEDAQE/EBwgzricDiFLccYuzgO7cjT3YzqHLdu8unHN4NTDU42B7GfLpLst2cWf5IYQPLpa+Wn23u6dzrg3dodnHDOfIxdpN+Fo/wABR3f1dVn5LeAJ3JizkULvwFLcn2SRre5RulyP6sTnEYd4G+2B/g84ZwvXVp02WWRh7fxLsKHVp9iD/bD8n+bG0PcJ/Lp9yB84DZnliA+ORn68nMjGwwLEwfxbbwfqa7RwB9jGw/ZH7drv8uzCXTyHfYy6/Jz8lLt3YgAsH3kHL/m1fk79jJDgBJ35atWOJ1aW8LkdyR5Dny/HJPtiF9v+Z3OPlmXd3xrAvvJZn95CWDdETNSZEz+WjxGQrUqCPtn63T7dPC1+SeL/AL4/bzydbsgWFPkphY7svx4xjbTOZeB643/AcshJ/BG5L5A3/V/1a/eTG/7nqJ0u2xgtOM/tn9k57dY6L7agz5sr8Je23dr9jIXqSeNqrXwv4W32HZUiew9eWCxwz+zgiWDYA9unnDFglPlrae2JfhervZPxZw+yX2x+xCLULa3/ABalv8nXthZl04ndu3a2ruyz+W58u3yAtkpkratbW7bf1kD7bvkK0QmU9t4Al+WoEgmahFp9tPpafOL/ABPVm8mrGB4GJD7YhC0mQsIFizDLr6X6nXyX8v8At0h20tOGw21bTx1dfYT7I+WvzmO7WClob7KtWzbLY1Z/bD9v/Yf7IoB5dfZYMSdQDaurM3T1MVh32EICy/JD8tfhC2vyO3ksqG2dexnxP82fpf8AF/xbA2rM72Tft0F1CX9Te/nnMH6kI67IRF/htfsr9gnVlwbtXl/Cx+lp+X/E9yN3+XcOe3sZkhu1mAd8GfnBBIgPy/myAbOH+bzy1Y/cm/GzPSAW/lsUsftpYmOnyyTb+wn2Js0b/wAky14N2D2QgLFix+Wzq3KZoUj+bp+X8Rv2P7nHd09l+L+dj5waBs/LuD2NpdWFi6fWEcA3wu/vAyv7GPZEF3vXkowywsxNXSWWILYZgHzhj+2l1+S/LUMuz3h/Cx+Wj3YQDiQ2lpbdLRtLJd7uV+/6GLDUohX9v/XgYgkG2H2ZoeSoNO7Hi2wbwfSf1gCP5nRmSsNtmsls727/AG7u+ObNjNkPy0/I3P8AcYJW2Mr9gSD5d/lucmk/qX4sXtizPT2xYScPdluXaRDfd/3YXU5ZGEY8lflu23Trhq3ZwZHAiNYD7D9WwDy/4nVp+Rt7bAYQMn8kfTBspUbFOOXVvDFhZ+SZP8kwLYFl0WD3gEh+yPkCRv1sH7AsJ21xx+3VpKpSxANhAJ/H+PIcqVgvyNfIRsI55CtZb8trN/3Zli3bt7AYB4H+Xf5yOj3gPTq1tx9Np4W4Wm1w04bawtswhflp4zj/AHZOrfy7zy1+8CyDhj9uv2wiEn8RAfbJ184ePcSZC22tZF+WvsT8rX2wm3kBYo64yjyWwT2M3zYL3k4u/wAhz/d/Sw38Hcb9v2YHrbD5Iy184NY/iNe2Un8ssntpbCM7eX/by+X05HXD27f4GkTQ98vxlpR8gH2A+QTqPpOcMcmfk0u5XzgV9/wjNicY155xOobD7PXlsOAxn94Ot38u32yyM+8BWf8AAw7WxLP20j82KwODbrkInA7lPkGwD2ws/kq9nlt1ba4IfLtC+cAuCTVnGzSQu0ZnCMgPyXPlgv8AwWfq2VgL2xa+QvsuMT+rHyzjZq947Ydzn2c+RqS/qxSLPDvgb+yj9sGazJnAXeyYftvFV4bNg2ZMO7Dg20uiyeTv/GeIZhv+pBxjLd6IvXy1bftknrotNh7bE5a+LpbPbT5Yvtmf9hWrF1dXaOA19kmr5a/bA9tIyyzl7dQbE/WY5iFcePNptnd0jfzg8RrYurP7dRr7J/ZmWZ7Bvksj9XT2GYPduzPsh8nc8sbpEGBMw+xWYG9unthd2/7KFqwNicX2z+3/AFdPsPXsOd7GZ/mQ2GyZ2+2pZwxzOnkK+xv7DP6vfGc+SFuyKSIR+TkhsvvFhZ+r+lkCwwkhSV+X8pLa/bct3yW1t4AR1IVl9kEaspwYWl6lgvXgE8TueYDuDJRISI0qD2NhLfJf2/7sH2Q/bD9tzqEQ/VjgaflAENsSVtfsrds27u7GDH2Xrq1asK6eyF282VtE78Lu2ZiyB+LBIpH2AOoIB+cceLa7O7C0+2/sBaMPfCL5H24QvJP7D/YdcI9GMgidvU/rqPzJLIf2FLIUuTaff8bX5ALuxsFrKPlr5NA9jgKPJ6X/AFHec2SckfSPwnD0Wnlu14xALMifzH7vxdtjYN/a7To8sQHt0fJ/if5jD0n8wkhZ4O7EMJbGYIPlge2253DWMjsNDmNI/bYE4eEfojLqctflvAMWz/spGY1YeraS8WNeHv8AeGZ3Lh2zY1AiwttsT+PYf26+yeAj3i38g/bCQ+XcP7ecsfYCFvtdfbt5IE584tCyy4MIHG93STqXyfzD2R9OYe5BnUviGXZNg27n4WzuDkwL7Bn2Ai5tS7xphfsF1YQFiAnPlg3nBZwP4sRuWA3fyel0jQl27jE/mxfZzZsfqPzP6cSXDRa/hwaJZgkNrLCu+pg2GF+7USAMtvL6sxE7lfkIhfbU3+yo/a1PI2EX/MPyY78jux+WTpbHslszr94dLPyD9sPsiBdHXGJDwZEC0uoxKm35b/IfK/pb4BLMJSMk3yV+3c2dZK/LfFqXHtoRvMzsDZx1btNi6iTH2PakErQaymxtvsE9k7yyy0R+rdbC0upS0sGwwSCyC0TOWMptZJ7YsN1fhCvfeDM4a4BuPfEdfYCxH0jDqG0sPLVi0+Qm3FYWP26WJ+QsX5Ct/suCHbxINrY+W3bBoEhw7sXRZ/y7DK3u6MkcFHuc/Z1KsSUPZECzL22s7Gi2QzRxarT7LYMMunH57EYtYPLLBYMj5LtvjX8j2YP1I6ML43w5JJC3R1xum3+cDflnxcSPkpu3s48j5pJl8X2ulLY5xFQLJ+IDPi5/8hCNTqXw5ppxZgWJrPl3a/JY/wAQnvgHgljGLA1kWX2xvijU66IWxr3h1O/OD/8AO0ezzC6trwVB3BHT236fberB9ndwPPbVsZ6uiRwwliXX2A2idRxi7QxzxVbO55HJ9ir8tPYZ/hJinZht/KHJT7yinftjxYezkWbNzJ7QeOMgFzxfUtSR9hLCyeWZHb/AYgT8yG6+QTA7dEu7bTgKNOvbUxv7PhY9QPkx4r8P8TzxNxmzIcjlUuOm7dWZUeo92DbMI8b9tIf0+nDLbE9ukIf94Bj8Io7w6unEbInvnBcnvxeJb1dn8RzHy7seLMD/AAatPd09t/sbknksbd+pfyyN9s2QziwO7d5g2SZxmsGc5ztkX6r64D30w6Rhok8cgeWke338v3Rw0tg3+MNwt3jLIDrg3xv+TxB77ux3y87eLL2n7e2F6nUYPL5QcMWIElt4nEKywEE44knBvFt0lhNJceBlnGSNlnGTzttq0buxJCNqZ63qLp42+jOeP/XDP7f9QR9nEM45AGYdXexuXT5b+22X4R+oIs6nrGW1Y/b/ALuv2AsLBkWBafOPR1Ytbdu1sXqM93vRIu/IEggyeN21heTjP9jHcAyfV42Xct0JttcAlrKJzberuZ9uk95AJ098nDZx5NzF3YNjrrPa/ad8Mtt/Fodx29v5YM94y8llLbsgbaQx+Ua8vY+z31GXS7+zCBvytcHJzptcLxliR7LwNuku5gHptAgWQQsyKRYWvy3E7SsO3fu7LI4bZpJktqS923DCfLE7sy4Vs2k6yXuM+w8AQ/mzOWwrTB3u9RBPljOkGyzq7GSjry2McF7ZwcGL2Z1Zxtos1t4Xvj0RjVqdLW7sbvcslkKwO7DDKDiajpAOpT8tDyBGJgp3xZgOLWw7aEInfsD7YJc843SF+2LqekNu3X4l/CGtYHlh749Gbe4bb4BBOv8AH8jmbZbCdWcE26PdhdTjdLYb1se2Wbq0Rpfy4CWtmurqQbOurs9uw2M9HdiMftj94ewZKR/Vk9ZLOoHMbbaSk35PbGG0+23RAdw+XkH7PHXjYQpbbkOx1YfIjHgVY251byWW4czD3uD4nueGyEN8idPbq6+TM7hmk9yQZOufGFtbRDbR5bFwDFrdW8CuRrH0uk8ALHGpH5G4YywbIHiGcMJMjA4227+yQhz5ajh3KbX+K5+zARe13R7bOyfsWo/UhttksY2IwcN+uDFi7dQWWWQn2C9kBAg8d/sHsxtCjLH7YPZz5OvsKxs5HVratrY26Tf+Jw9wQIy42Hxs4HLtep6kkl6ZP4cx/T/5b/b+kJe4Z3HkF5Os+TI7Fuf1Yu7v5CkyO/ZcnHy2+Fp7tQ37F62SWfkmW/ss6IbbFxxqh9oRJA2ExzDpPLLLyIqyftl2mWE7vOBTx5rTB9inD2Ee2Pt/KehnD022FsFd+QEGwB7Ee3Vu6tn+ROtkTu9T0vXd+toeWSxYsSYEhhJSXbtOLR1bf9XT23Jpu39kMPqQRyNdsGdc9tYUwxDloxqTILON46e2nuDYxbyzXCP62Rj/AISjPxwJNwZd9kgkt5Nzi8jcszNu8NW7R3PaMdXaaS3SzDnrjtZvU8Zxk8kT2wh20/4bjuZcu2w4zbMh/gjgM4P8e/2NPFq3hN22kwjr28Ht2uv+U9LNvXITtHfjmyeG7YfbAOuTpbv+wgkM3m3bIMi0tlwu3kP1GYuBMHBjqeNrjbyRPGq8bWdxw8BCu7M26t9LS1tqe2jqQd87w3LtLwPJnri8nXHb5A/eMhY+3XizFIHt/JassYGUwZeJ13aeWPCmOQSwnVpDdJvbavKyPZbNmwj7Zke2ZduuAXSHEdmwdFn26LZgQXM//t3vxx2zbKdLyfYSX/M+9z+LeNXj0tkeB2mEcXe14C2mXyyMO4ITghn4L6tmcHXt0nd1zqDLlrA23j5zoscBBk8PttuyUcOpdMJkkqyH6tL94c04/YOg8cjiJOmz6vX8kMwjyAksCUk23+xjjtA40t4ztZiuR+oF8koMHL6vCXyTLTyVGob3GIBYhC05XVrANjiBZnDZZBxGyXTsk+z0vKxbzpK53ke3xYq1ts4wguiPerd4e7LJx1GWHHtBtl5GPB6n/B/1Dtncbs/Yzyx9urJK+eQjDrW0xqzYWmSkpbZ2IT5zEeyW5Il3yILSyzh4UTTtNeowZ93E2LLLG9L/AKsyJ1MrbJuSHpnu1BzLAdSSMqWoTae4x7xhYgB5YnDggkNq8hvbu7khRd4FLZdWtqRYLYOoP5YgEs426cFwwRBZLau+QZlpGHAEBYg/bp1wtulj8u3BBIbvkvOnhr+3f2NfvPbePYLECA/J9nhlhPUepiukJZdsAfLT2/KVH6htviQN14eXTbnUxOyba3dm8elm3l049uN4baXL0Muxnu7QkYphpdL7LGMRuYQP7P1DODQWWN6RZE8EFlkR1PDvgPsLNgWDyJwhJVkz3nDLCzC0sE74LMfq1Z/LTEy22ZctZJIdWySC2oKGzdw3kDe9F5Fq9+THeQ3TyP3gAtiltjHthYRMCZY7ssngIXcndgZZKttt4gJD1Zlt+EkJusCGDZ4bNLeCxqQ8t2yxxR98gF1x1beyb/gvDqHLbW221Chr0kfJT28JsJyPq1P64NdwKBzvkLLFtt+04Oki2R1JskuHHbNtYwjmXf2OoqODVs4avf5A+/IWEywbJsdomC6dW222xzvDMEbYLLeBBt7meG1tsiZtdGPxH7gk2cbIPECzYMiMD/D7/nx+ln7IXU62ni8TAHtl4BZBy8jdbHpbIIM41/ZXDyDbp/oas2Z/hxEZJD/nUEQcblq1LvCMn3/I5bsOuOlu2x7NvL2lyNMeXe9Xf23vLBbvYj7PZHs69BtxywsaT4JjdniQ9sLr5/3D8SxiD7yIx/ntm9TizbMmOCDrg9nxlm1DJ1Zl6sn2CTINcvJZM+R7Z/r/xAAlEQEBAQACAwEBAQEBAAIDAAABABEhMRBBUWFxgSCRMKGxwdH/2gAIAQIBAT8QYetO6hO7dgd4ufbk/vbHqdsLJQfA7+bFPqkNbla/yNO7l0bCwB7nDmN+PAvlA9Wy0cC34yROYftDWyHfh/O/HwOfBY+oaNEcp/dzdQHgsdi9qDo+AcuEJ7OJhBxHQ2nbliA+2Cx9IB849aSOJPTYdsA7cjPTO+pNWVz5upx7I+E44yBbHVk9QOyuRwRy5JydTj1bc+X8Xqxk7psB0WL3O4Aczvp4nH9tRuwigTkAsvqCsZAZYuywNIvQFv4/9v3gDluzFskD3ZPsH03YGUvQlvSX7M9QQfMhKj6yb0XpQff/ANI+MneSxi69S3sJ+mQDy8QR1zY3mfSQuSBtD02Pq07he5OxKeizeyA6sOsj85vVgDmU9Fo1I50Mn3YlLbT7D9tHVqtHZasBnNkUn8Ifth6eAe8twe7B93sMgcRj2S77tPet8OLf2J9zS7Bnu4d2fcvS766k9snHUfpfmGepedRz5JMdyDwyn3HQyHqGPJB7h/u/qP3A92JZ+yPYWUL1O/Vt6ZYu8uXbftYJDttLRsfIPkv54OTzCRQONbF7h41gOcs/UNwEY9XJ0X4QexZ1xsHdh9sz3YdwpiyfaPftl1Adyi/CzAfL+PDX1CfV+kGfpIP2PVxDwG0e4w9bb+T6oHshPqRb2Qk66cggbyM6d5afC5HEr7elB7LL5iQ237kdSD8hFr0ynTJTn1HsLl6h7uLvwHHpv0gDVvQSuCD7kvcPRtk5gHZKdDIPuaPBfjHACW9R+8konqUe5V0wnbfaC4Jqbc+4PY2H1Fbe7Tq4fZEfzLvGlh7YTeZ+q7XN76GeGZMoj8k7xki3tXF1ZevAM8N/EA7vQvtZ2nkf7YzltPcadwHpsPcE7jC15b5MFegQvhfAJRtZoBb9Wo/1OFl7vkxzn32Adtvo+OIDZ+WnrwQdt/UeKxPnfVxExr7vcYHbwIfk9jHo8YTq/wAgHd9rX9kjxbhW/wAl9ZChsu8Csi/VnGJR3Ju+r9rMh2w1n0WvQX8TTftgJ+sJaPuxAO7P0gfZBfknoQ/uQnHu0nFn1fEGcOi16IU5tUj1GO4+rJY++PLq09wkk6jDyX5QHRexekYD3bLnzmcfYD22Xu4+wLF7kDqG1O/PEB4o+7IkIpVv2cnFuKf7Ye7F7ggvZOEtcJKQcyPIbT3fuxsPUfS/SaFzae7A6I+Yx7ufhs+7S0dxPsCgOY55zifRLPEJK9wHFv3flBsHt4fqk6kd7anu4dz+I3RHpXLE/e3gZD9x9S/4n39xrrbbyNnOOI9oZvpGu3xvYebPRsn8QfhbZVk4ZTBmWHUxcMzPa6TwbOrXuz0bT3fzGfV+sP3OBuwEh4Id9wL3cudg/ZP2xky3bb6RP0YG82WUWLxkryShA6ZcjqMepPtp6l9M+9inbaO4lz1YHjLFkdyEN0Snyx9s/wC38yjoX8Y+2P1DxzOJvplvza7SCD3YteoZPzufqx6R9Eh0TzO+m19lfbYd2XuOHcX1fxCb4LGaZKejwNvdhzcvVp6lXMddSzWPtj9MT9i59kGU9Smyh+4P2De4SZPFv5abcg4sO4/wtR+rsLGbhb+ztu8QPt+m+aDEdSdCPex7GcPACeIjBMwjpt/YeGth5vclw5B7ML0s/V2BxGHebAssu9eAXZnEpJLqG930chTu7JCcnJmwPch+221I+vN+RI+C6WnoX5CB6gHhB7L4eA29Fi9W/XVn7YH2wLtkJ/MP6hO79rj239QYgOJenLjiWH3DjmXQbW87Dvphw48QemF1DdlvFw6tttzsfFp7hLPXdh9jDtn1yHVvBI8vdz7YThfzepYdsbNgckg+i29WLtuPTYls+0J3a+56dkfdhtwgH3yBv7mDT7tXUg7kerkkkfJberIw6JTqPzFLkqFeAH3Lni3j8nZdwfO381h+rGfdfK0gbWx7bIJTFxax11diBLTO+3Gy42N4k92z/t8Dm19R7JQat874pjUifSAnLfjZcSE+lq9yCxejwLeEQR5v48jH27+8+mr5RcJH1aOPAlYz8TIW4LHl8XuyDxM8evMKxuffwh9L92U+ifdL7jrf8UeXFr15p8x7GY24Lj33DG+EQL1NI8M57tD1s/zLWCsN58DfkyerTiDpMvl4Qe5El3S+dhza+AWpkh7nJ3KvUWQeXiCadWNmd+A11C+xnt8Dj1JMPM5QfXC/Bejl2TKrxvZPVBd3xn1MhwtvteL39vVGH6XORDsXwnPZrMGhlvk2oX6ct9rUM/Ceh4W76gjts6ncTp76heo8TsHZ4cQ+SxjuQ8meW0ZzxP3fn4G31fuOiH7Ae2ATj1CA9SzxcvH5Q3E+Jr3AO73rHqUMmPi2+BHcC095bNHi3HUvRCeVhO7Bh/8AZcPd+Fvsl7Pu2FvMLA7beovl1Kc37XA4sjhKvpAF8FtjHdn0Tr6lczLHepRAe7B7hr5QVXohdFy74ibCwch4ZF7L4SFt1Z9pJ7nHUN6hnck9WcmXD1PwkPU/m06Jnh4kvcBeLj3YcSPRKvBqd203oWlzYQGQEbJOieZ0X6y+h4oLtm+wezcAdQi3NHq6ObDu49EFkO7fq38hPqwnXM6Orl4lDO7YM9X8eOfSx8lLDpvpgHfhj0QPqDOrS19nNj6tnLegT3NvLUuokerPok9lz7I/Fo7CAkr3/wDUH2Q8XPtlUPLxfbwAvrZ45vqWerCXvERlJ4HFzTGHlhepPRMnHaOgh7kDwo+yG1Org5uS0eevFjxGb2SQzmR+Lk6tvLY9smdeA7Gsttb9WYEQerl7uED74wutiw4zcHcgtrxc/lkcsR1LiHu34snPzacR9/8AiKTMThs3YbPux8ZHYkONkdEtZuLo7L22dmdFh7iwMzLa8T7zcJPxjoTnpL+GWzpe8QFx1LIAywvMPcAIEgSxwvwTrt5lPtue5K1d+EFD9yjthfuE6nhc705akyc92XXMfmT55ECn7bf1B9th3PogCxBspvlb9sHu7+AxPuJAgpJ1Ytq9Axty32Y+W5fdh5Zn4WfCmL+Fg8dSvG36yTWx47iOQ0GT45sZgGZ7hOW6RM93B2yzYvZZbvuz3fpYSLuZ0Di5fcfSMeLGyho3IMvq2PhLWvcZ7g9WSWY9EplbPjLCAc2JXrwBtp1byw1lHBb4QBJtvuW9eAssXLTqwtrWfVDX36hGEKhzmwcMN22r6uhcwONvpD7SziCd9X4l9vvHxOQXdq0hj7vV3bfYgXUAY1vWEn1Kerd7tI+yAs2WHssHRL9Sq1J9EbsO50l+I17PHW/qf3OSxYHFxuMU4zowe98GkY5ZDq1gHch1Puj2F+Ecx8cPuw7SfTIx+WyLcaMsc1IxVQM5BnuoWV+H9ubS0t2Gw6gXM4nMDwnM7PUh2JB0Sts6Ze2GyXB3bN94G04h7I1g++LcK5QPtn14cLfJtfkA9TiylyEuyYRlN+th7v2muDgg/L+fAGnksSXUY7g/LV3DckkfA9IRH4WwHyXKViK5tg27wWtto06ggP2JD3YLpHPXn9jJXMk+A/2FUWRlwk3uQuLSNyZBi3C9Sg4l8mXpaJbbckow/LLX3E+z+pROLT6lwzuD3MCPUE8rfuwWo8RxHplvU0sl9BD2ZHZbzH23CCDOo3Nydurvs8D+W21Ps8EniR2ynnyJM4Z4qZ9JGhiHThcEE3LcuLGG7xiLpyz5RY5AOrD3Pzame7fgbPHB34EHMFJPfhCyQ6jHdh4hhZJbWxj0EU09SpS2KQTHu24JdgPBmIcXJZmMLnsagnux/s+6I7Z+9+lnrt7ZGeJrM2mHV8mHfcBsWWzA6JWluZckhpNtbl1Knws9Lmu/5dl6m3WeiQ7bkxLZ1IPET1H2snYnBImXbPuLw7sLkPULdGCOreHNdo7tJ8RfZafJjdQXuz6kyINs3HnLTM4hN/3OOI6kvST945HudrIeS/hkfAjuRn5b1iQnUqFxNB7tPANgTGAZS8x7WRt0hOn1IP7/APzJT2//ALBzwB3D83HgdZDu6ZPFtuNwdh0JZ6TvdhnUqa9dxu3q7DAkPVtaeW4yucWyPEvt3aW1rpb2R4EPFpxfSValO59yWlxYtO7EebvyvU5y4OvKFsJ1OpQ8Qk58KG1dw+pMmB4EE5OpGHRIYzvVOmRfZCmEk6y+VsC6tPcYe5XUSOYQ4jO4A4nC0d+DsMJ1MvpHGAd29XqPyXCT/Fk4gu7hDw5ZBXuGzj7YfbclMi9+FPVo7hOEseic+pNm29+MxzsYObk06m3Ofc6GJ8bPFb4wtIuHk3zn8bsLCB06sOZywYQn2s492ELkkIeoTynB1ZbxZ7RrqOfJNJ3gLTviQ4O5ZeZzIDnNhB4Tj/8Ady8nVhadWp3I9zJxMaebtWo8AYN8eXgx/Vv5Db8zj1beIZzbtTT3aclocbsWU+PVu18CTOTbaT53yOckx9hIUHcYXR1HLlcI8ly5i8b+L5IUfstPRPCzi/yE7Ix1NmOrInji5hyIMLusSGNLVduH1esk3uAIcy73FzPQdWD1asJ/E4dW+Eq97vvwHbPyB8BSPdnRfWEzbdx3GDsx5jmN2bM4ksbc7sS71H7/ANMCWwbnP27RLJH6SSPAfSQz0oygiw8ZlcWXNtcwHV36viTvfiE7tnle0we0J6hqNYd2/Macd3HY+ICU3uJ+CF8hsr8kerU7h+GY16tShOce69hbudLJ07kGTvoz6Julp3E9Wkt8dyWf/A8+JHWnVyeIJOR3MCUeLPBAXsQvdgsNAdQLsXi7+HXGOiPRcTmzY8BuMK0mieC1ax7oV0U/aAOL8W5WK9sgeL2Nr7b+wqWTnuy6Zfpzddk8luDm0Z4tBh1c2sBjjqGyzw2PDxbvnf8ArQYya+BdbJWEciDmW2BzaPqMsIyA3eLIh4fHt+paA2XThnHu+jIeJRH3ZdyyBYYc92xx3fZOepSQ92LCTa9XCR4sFqRY8XCY+mXLhEvrm08SHEMRjBk4ndts+QO2haXHlvjJJMjE3clcOrS5+yYdu7g9yPUqkMYzAbVJXS5pTknQRmR2J1slxsJI4xv03HRh0H/26LBDbWR9zZ8inBAOrEtrROvAUuxArA5Fki9ShzK9RTXubJ44+oRkdQYBwwPVh5DwC2sLz5s+A+NLeiyGyEBZnUOW5LZakZVk0Q/cplwfcr1apL1beE5827AdkFm1Velfm1H036xCHUqGIVhbfGEJGdQPqPXyLtMs3KV3Bnh2FmNZiQXqD74yxtnbn5a+SJtyQsIwJAYW6ftqHPBYd4uEpWyrvvx5s7tSHUcoBLni1MA6uHZVv5PZ49u4ejwahhP5D7EfCx7sHHgHLFrceM2BIy5dRrxD9uwllFpyZU7Lq1tRyTEDJnEfZj7ec/O/OP0XHuWN8WdJkZ+vBE3n7serpz34IznwCd2nXgbgfbQ4sPA8JC5Lh46PUhtP7C9CQbUI8AeAcbN7IOpJHuPB7jwljOvHigsScQBnXUw5dweGYTROS16SO7JXzwnedtrdnfBA+7bDwjrIZuTlOCA4cyBxKHUcrS2ZvMh1aZWJT3CtFy827dvwZwtTyhaV6mAaWkAd2nRE8NoWJkYjPgPhzeYmEJJCN9WmYSk+sGuypfqXwhGyRws3mw3olmvvxuF6haCyTS8ez1P5NONjdjmIUJFhtfbcv6WvOeIPAIgjv/kI1xJ8gzvwOPcHtKHHV6IubM9+HcuHw4fOB+CZb6sOIOn/AAfO6RcLhyPe3pLrYuXA+d8THnOvLCUWw8jJ+rFM7ZTIYT14rnNy3Pn/AIogfdjOI8Sd5k+p53Of+Dtr1EIjzagdO4Hg6807Q5+DI+oYlZXt3m2IN8fCG4+TJdTytsL7tJbba1sfGFmSaRuA7gHqHxfi48Q7HlJCLImynEHaz0sgE5h/Fg+EvO1WJEueCr4ZnFnhng8rLckPgeJJ14YD9n2Pjb7ce5zOIGM9+BQ6kXJHD9uXmO5gPqAclqxqITkHHPk7wMn0XHuR9yzJkpLIiSdzzDecnJMlPDjCOps4tPLcMiISCxkWdXbPHVjZe50y4yGCRsHEFj5cWpLiETfFXq1sbmYFhuMzu7J6WsCyQkSkN6hnDKOHUlZIO5+ltOruJJ6RMlpGe5Hrxalvr4ChWDicTrwrzBDcebirdxKmAhm0LA4ku7jA1mzZ5j4asO3IYRh5h7jrbksHmTngJteFzUHiytpyQWkuPJIIb5mN5gSIO4ulvNRhzCZHFj3LQHF6Jul7m1YWeGrB5aJQkOvXiO9WHdgmKLbcK3e74offGEIw/kQeNkDC0e1hSGuWCVae50tV0kncrKhrasgbMLy3XUWDmW9QaSfJ2B25WPHP2C2/4vX4sZyEPd0triF5btoRcIHJ1LnxlW0sJBOy4eomlwnEth+RdLlC9xRZuZt8awuzyYxhmNIes/a29WvdmQ6jxvgPzK4l7ZGGtiuhxGXOQudwucDqXJi2Mg6gppJDtztbVraPfEp6jEDuyh7s+54RYdXDerY+pU47mdwvcGTO5Bc+IPE9JU62XOBaheEBLks47h222P8AhMIY3NmWL0SHZKHEk+X6sk+MlHFrDkZdOJlia6kJA60n8Qe5AbPwSs6mGI3Lcl+pX2SBf8Uz0kvcNe5RsE7knEj1Ou2ze4RDInEwbGA3MnhxLZbTGsMI7nbLfkAgINm0tiwx5whvgg76l6DGN2OJWncmYipWbkA2VJYOYBgjGNr3cLCclJSXLSHLYMO9Qp6eQTjDbfj9Jg5zZIn2R02ntsQvSRcpOCO7bxKvTPmZGzmIG1aZx4u49oa+DnKdSGNjbW+BcWkzSzAEkmBGcOwdtS8kEGnMA4wckCKArC2cb2sXqMucpl2zudFqaUnMat3S103EoECS2HuT6hMosYTolwcJzUZnEGysB1g6JXJbHUgqvgYEWXKweGZKHdlmDwxvjLbZPS9jAgeBikOxArCPGNztmw92jpI+wTvf9gDqLvEK2beUQDXuNPMD14HvAdwepC03ZMe69CGYd3DxCeGWHFuHe4LLLM71HXsa7toYzydseC2Vyk0nXMApwJ2xeYPRMTNlSHLPgVHN0i03KS0gZMORqefGRD71CdQ5Yyb4CJHfh8kBb+rGwUaNkMgkDL6JS0xuQOytkOLcp5ls82HqfWJny5LblZvYyTvQC5g6jeze56JQN2G8Sr3d7RxSLYcJ3YtgOCECYN+7u6tIO3ohy2LLW1cotHIcvgcbKVa+djrxs6t/blKszxxgt+rXxW5bd/MCAbn1D5WLvx5zYxKBYbhKeCfMy4gjqWx+2E5tOBey1D1cbkW3hzYCoEljn/yfQYSWXx6/tmE8duTDuc4POYTvwadTPd2l8q8drf8Ak9zmwucaukTOGXk8EfaTtg6ker9eVaTDA+CYSq3Hm5Y5bbFw8V2XMeD/xAAnEAEAAQMDBAMBAQEBAQAAAAABEQAhMUFRYXGBkaGxwfDR4fEQIP/aAAgBAQABPxDCSa3573sUPOuhM8tBIIdFQP5xWUk5LHW1QWEd58JTtC5beEaLu31mO/2VIkSzCN/jVlOxPipPrGACegppWKHJP2zVi/0QJF71KO8RnXW+ncrEXzpuJb1jWcf4KkELOkHfWXOaAWFv3Q304Ctkr3+ithmGR8lajneMWxoKzeXB0Gx0axSefoD4rdFpePePirh1B+ZJ4rpwCzwgPqg2RaROliKLczcT1lQLnBQPZ9UEm4eDTNvNZI4Ajo2aJie1DPLBRWG7h7V6Kl07psyHSV80fd0M8KPzWPO9y5uxRsKcB2hPus0nOD9ip2GHbwJSKludeZDtH2rHaN3PhPis7C3RblFARK7hUnaWatZRiVAnNwW/NQJ6oRGyI+uav5OGB7D00LKpl/UE2etFiY6IXrD005de4s/RVHelk9crxAQd6tSQ4XqwolzsvlNTmPsB6k1pW7HtWjIIyhfpfbNKTx0TxcUNY6Ei539UPdjnPhTzL8o/m9Ieyc+6Egx0kT1uUPU9rK9Zc1cWRuwfS1EQo5hnhoCHDZhHXm9bquQ+SkMiNCw+G5RVvHUg91d+bJHUmoF0cBFBlDuHscVMKVovHhkxOaywAwQPYS0yLjWzZ4mKQ6W2Ed/itWl4fmzUWOyM9hIPQq9vQn9+yjaRu3PMqYsF5h8J81rCBwrHW1WhU3Gy7SxT5AiTAQZsMgm051601bmxfJRL9AunXaDtiKMYjRX8KBZbeV7WHlKJWwxEITSJKEGeWgJ6DNWzhWCd038UHUbgnoBSmHuE/lKUyG0L/Kfp0p9GaxRsBk5vUJ4lf8zScl0fmgGSc3TvgWnUt9JkfNLkE6ohegK0F3SZ8/8Aabzp5PvSNIGYZfsF8UOZbeflimFw8I+WjLpsg/JVgEFpQu1473rOm7K/nXSjeZIpTiPmo8RqkE90PdOo2/wBQuYyWFdlC01bX0IVe8fdKO+KfFXpXbD6rN3qTHQYohID1F9bg0Ayu3DxMUuYY0m3mKSbJN2noUwhJqCfNClQbQHt91fQRZRWNhvREIJpT3tPdX5QdBPTdU29Ep7n4rBwf4oYK0NNP9E1cgFmSnxU6NWwzyjxQ0Azog/xT1yyfejFCYA8fiWtqxqF6E0pAWxFPB80eNzICJ/tAkBaI4cpE9W9SxdGR+HWssziC5sbVjAtVu9xoynWFLOqE71Y9yN2+SgDsgHgV8Vd5/CtRUydFE8FIMiMXHsxep3hxCX+ULSxsPNqHy/Nz+Vmc5CHiHzWLdAT8rfNOuU1+OIVfklyfBEKa3aMegrfHxn5VgHmAX4rHWbqPeBpOSeWJ7jRonFsLQlmZJzxxapM6jCscWKBwH6Mi1kGYmJ7j6qfJSRB74HZyKCDYvlCUYCXgW/YVDmBvN6lQZlbewgjulPLrwPCsFObQtvD3U7ie98cE+qcyw8EDishVw/ym6BTVOE+96Mv+GB8JhTye0EPuh1kbc9YKx39Lp8lqGbr4MOwVEUbi8pikO0h00+6FC5Rc/L4KMYWyRHcZ+a9DkeQlM6fZg7In3Vl7d7rDw82PWP4qwgcF7KnavH8i6CB5p8KX/jF8Vqba4XWx1qVYB1N6h9VG9F+c/FaCu+EiNrGrItyWR0StOLgTzC0BZqA/mTmr4B5Q9CzSW5OojQqWV4fWRBq5WGph5VaLDRQ+YVZFtRKCoWTJ1s1nSLpodgPcVZL7qi+Wyh1dkSnaLeq1461fUViEOxK/MVFgSMNXxD5pWo1tHeB+6ywfhXiiS+d8HuaD3C6dqkE/ZrBEzMB/XzVhBNyTVgEnLPajLQd0HtWn5M5lehS/EYWHrZVwDokOwzQckHAHy/VAbQcM/OtOI3t6q/yOhPKT7pYSriXX/lZAXiVMAqerp/Idx0ovm8l/lXIY4sfDTFjeJEvmsAmGpStZrsN+tmKMdje/VLuwmJYdbaOlWt2eMet6vBH2RB5mhMpwSeyqZENbzL7XHUqPKukJ2yYN6McXKKOpJ7qJdI4fmWU1OtJXwxU4Dgyx20uBK0S+UVXEk0ewkBjzWFC0yPdagxHxGEdaAiY73/mlB7hpC+mlEJmyl3f4pOOyx80GbJ6fEGjiQPIlGyi1SV8F6lZl2N82nfrWIluLPto13Nr9qD3SBCh0PtNCXi1fsn4rHXpH6+q1T1Ay8BDU1A7UE95/NRGdl/gQb7qIQsH+aDRYU+R8UElw649pnXrfo7yB4pWpeMXs2VnzjlH3GKRyHLA95oCWI5Zf7RYLvFAyB0nDQMvKHciiGRyXukx6rLXuR3aSBzRPq1pV0B1iO+lKrcaL/cWoqPQFSPHxRMGjN4PmmdbeWOtuKghM6kO6+MTtUs6vS5hB7oUkp59DVzluuP0UROnhBfOQpqw9KRe6G0+haJpB33+BmoFm7IyDw1Yom1jpvVqdyXekvQQsjGEt1pIdy5H/aHLqT7WrGBcA9TV3AaCsHSGtqvLW7uszFCrmygu7Jp1tsFZ50KMIp7yDzLaoiI8YfkJrX5w/tIoEL40EeR8VesnV/JScINY7mke6IIHrSOJxQgh/O64iiln5sntCe6ZtlwccRHmr0i8CHos0+8txnHqWoFlpuTHvXC9KsDFsSHSBp1lG4h7NJZE9bXSnSagEvh8UFINMqtyAU0TxyB7KtSPUp6kVbkB3e9irg25RHvfs0ypB5+jUvO8RihTUd3wk0Vhg1g9qK1yXH/NXJHy1AMKRa6PTQiRTqqDwweCsw273oTSEyx+PxS5odWT3UeY24elfVEI+HjpY261JkXwy3mKDcM0ijqrohf7n4CTzSl+SPEK2ijVD7rXBrcL9q+ulROhf3RsERkaPKVfE8Q+VTG8839VrYcy/etOi2NBTtdh7r4if2q6Pug6Ru9RI32harcrZm/DVgd0QR5LQi5LLIEdKTxUuhZ2qTYGzLU6E20qnorgkJIHTJ5KAu9eXuh8lTBzsmDzWhUZVZ4qNkm39PqsIHqf8o1w7l9q2T4aPFGTKd08NGZfMMr1wnSKmgFpZ6sUXaRjBUY80n3etL0wPc1iy4DjvWkLyJ/tf4B/lQpImFYYzdYzfOtI8nlfE3KWom8nqmjZpBnrMVfVrNiHw0tkuI/4FOJ9R6oLJ3Zf5M1cU3RCcXVAoUcMXa0vFJD2YPUNf1yo8z6oI3YiTX3iKyeqwT80iXBwuPKeClJFbhIfdJfO4VvB/lSZiB0beaHiJ4zPbNHebQY6S0RC2jDfDep2wCYAu8Qe6hM1sh+PwFJWVX9CKAkhpCo8g8iD4kpW4G5v2o6Ed5ud7vVT5hbLP98VYFTsfNg802bsA+tPVF3ZszDPQ/taKrcJyGrKw9CKLnxBjvTfyPa6lrpeISes1BjJm7/YoWRwj5L+bd6sUrWa/wA1ljuvXaSFp6WRrm/tAszbnsgq4Qcxc9UvXnRey9LylLjdeHsRWAg1VJ8ovegb25QXwRQHsTL5tS8tPrId2aLaOop3cEhjpFCcpPCvqCgCE0bA6MNQLr2TtaiMGGEMdczTPtIPlPurIJ0cTqUjGpsUuSDax6rJBukPqjt2OkPutEH3r0gp4fiQ+S1ZgBwNOWAOWPmCsc74/inbh0R2mkl1c5VAbnRDfpBRtz2IQ+6TkIU4UPdfvP5+qMWup+BpAC3Y+1Dujo/2kBI21sozAmb2PwtA5OsDHtoyQd80W/Nol2mswMcH9xV2hNCJfBTGGpChvrAxPWaC1jkvVIE4qPaPmJrdueqHhjUV9gBRay7G7SZeWaOPWWx0qIYC1wsdAfrUCwJ1X5Qq7LInVHdCjALyAeF6afnOgfYCrAo58heh8jaRe009LHmXqasKsUr45R0p7F1BChBCQ1jPF5+tVpHz3jWyeq1JcwSV1OO1MZTe/wBKE0DuyWyK3XeKOtDcVztePdM5C9CV9t6h4DQH8pXTpg+Md6dFxpMKdY1ovIaWrO0/2o858D6ms4DpAv8AKvio5I9Zkov5IdrDTsMzRH22rRBoIDpAlPlPWc/NCvau/dYaNkPzDWGbNkeSLU3OuhvgY9ULh509jNClM6iP72roPS33E0q3Gdp+IpSTkMlXJtaSTxL8VGQYjCJ6JVqJyGXwqSvCdD5ilMIDViP1qd2NM8NWzMFLIO8YeZpi8h1nfrDSRCRyTFMMJuRWPNW4CXEoz1ab+Qvj53zViyGkgj3WqhsepKmIfkXeQrCOd0H3Qli6l26QFWJZi4Y5m/eaxnor+SoYXOhB9wUB3uR0s4oqOak/2hN3V/qrpOswCe16uSQtI+5pvXTpYC+s3d6iX8MOJiru7kaIGXoGz7pSUeSzPLJWtYYyHwfNOdXm83jPDXPAmUZ72pqSPRLXaaVqeiT/AGr2xdIY8MUhcdQj1MUCU4zKY7DL0KCoxro+YzdtXgnEMdY8VhiGJAHftR5FGZJfHPFOIDR+aculTGDxj2DQC6zWfuIfdTpHobvcu/GlA2D1iMuIkk5qxqnKS/lNkm1O3r9vT8zeljkblKEgXfY/0elBIcGx8EDxWjE2GGJ2v81Jfnsh8F5pyE2WNiObijMCMsvxRhsGWbzIAUZwcXo95U5qNZOJMHiy6lHKwLaFBpJJUCEDqvf+1eWtbLxK/FLDIcju590TBE3n/taxZxEe70xul9oPNAzGoJj6qXunf7lIki8o+z7q+yOovYhrOA2gPkv2oDI7zAnpelavIu7xR9Zwr5asx8z6Kbfmozbz9UUtdZ7ihWJ4Ig8N6EQoaavm7US6Nkx9ImgWElyBL5vSJcS7HxVngJoHkEOgPJRgTF6hfadaZ8maNw2gk0SJb4bLbqt6czDndt1tDQ0BHdR981AmI7K/ykkS9ANtL0tfqF+6Gg2HKdWKNLJHeR8f2jL+FKcvhksrvRVozSH7imy3ple7Nc16n4rA82fFJCaiGSLvmY4xSLvMhPU4nm1R5rN0T0lxVgUM2jyigRHO6XQtcavzvcpPJVlS3JPYl+WkzSmqTs05PHiTtQLQ9Zb9N6CgWat3iaaiJtIPlpaZZzmnusvJxdJV6lqxgIsqNt2Qn/KeWjZN65fVHEp3E7vxVrEcCJ3jGms0xiyMG7TFEbk7FHCWheI9xrS3Hobq8UxYPARPigl24wz5rQ3K9jymrqky2AO4ekGrWdhd7PsioVo0BB4o+FvJlC3FymIEXsNbmWLGlWwyTeRvAZo29ToM8/xV6jMGc73+6VdmQSByCeKxSNkO5OlW8B1PmSlYhwa/2KnTD1RvGrn9mpDA2stvFSuQDACf29aMutfufFRpma2PejtRNhH8EseinsQ+JB5KCJ2AB+Gmnxg6pHxScvRsaIJBHVXzSuexWUObP55ryRWPeaZSozJHuL0BcB0D1NKRlttxpvRiQNqbdqXMcQ7TMz1mmrtf8YaJglGqO5QbRF7nnOnakoXdLJ7lqz/ace8O9Qs9mRe+L05gAxALHXelpQdUT9Uhm42LPDNTbdQlfFKZBckfZ81ETNtbZ+3qZIzSU9imZgtRa29kHmsIrYVPq9WLggDHi/co7LdASXpKk1NhJ9NfusS41TwlqBCBqQevXvW73UUc5igXOdpnzrWCIcqJ2AaUTBzMO4H1V0NzNoK29p6NPS5MKTNPQHMQD0hamrsvqeofVAZC5gX4tT08Jt6XKLYmNU/CgJK0hzwKzoNi8E8h9VA7Uiu7L80m+MdG4/VPC4iZSfu080twmyv1SFxZ37bzp3qwF7EkbZzLUsr536qKYAmUx7YoweMIntFLkFwY65amQsdWYeMxQLcSsoR4TJ1qxzruOuiaNMbWEQK+D3Wg4RdHRfEtWqHGWTTFySo7IvksOts71LmObE9tXxRSBvSTM9FDFMMV6vqSkV4I2C8YpTDaTf20MlKdL9QosWSahB2lPinEPoZPtKjyH0iPRnrTSAnEnxmtw9EPZHuolh2H3RFQTMTKuWni74yj+0Ut3WWZf8KCnIiSrfJzde9IJk3oSOIq4xDo+ayshoKg22rskyQe79FWYXTpa4Aq/o21hOjNJF+6HEJDbSgd2KWzixPTtS2OXEjurFFCVyRlvUfqxITxD4r5A19tWwVxYOMRSm+Pb+dqm1k5GOlvmkbo6ADvMVaZQ5R5KlJq7um607DpQEx91JRTdoNcEbq8oJRMGxlnuspqI212UnZg9VCHTMLrG9QchwIPXtNEZtE4dsqHKYNiGOsU2pvwUESpdcB2/wCFaMG33Hur8PSq+reqEMXWx5mDwtRZT2D6TTsI5I76XrJo4uXi40WQ5wfYeqCjN1xfDxtXbJMDwn3RS3etvAVYnqIlPNAsR0PFWq64QerViFbwD9RGKenzS/pTD1hQ8SPE+Z+qGa8bNzecVIR2YHwXikLV8nDV0AadvNOCCYZbs7dKBYkg4EL6m/eiUORrZJ1lt81qNwi97pPejEw98f6UywVogT7fqiUEToiMTarx1gGPm1Tl8F4y8qtTh41BXmxMdaDCxsoW1vSmHsSWdNovQmTVX+U04rSEPAHu9T27wOvaKKtFlur8lPWgG0L+2xRsu4kA9xNWc82sK8k0CnE7i1qReW7MPinbR5C/IjrSj6ExzNF+yv7aXZK7I+qC2d5Per8kXQIPurE08zM/2pGJdEJdf8KXgNCGHiFqkAk6qk809KCdl83rV92YA8SJ7DTxz7hX7DSlJrSpbS6B2tUkU6zNZdrpoMNnx83qflhqQoGCCaBx6kHul0AjSLvbR9wEzAPK0xLJ0mvMmXxWBFbG9i7xQE0mi+8LntOtT0Q2YdhqTCtqgsVNdZbU9lqzoPZ9D/KsCGNgQ6sUgWxIswR4KWE8QsE8lEPaQOhig3tCfip1sxrcWP7WALiJ7aViw6kEe6mSnZrea8xFy4vN+Jo2T5F7ruBLZ8hRllPSmPfuplW7oZ9NYMHl9wUivOIUqYkD9dKs4TvKPQGk2t7B2hzFb7emx2xSt03f9ms452fOtAYqy5GIVC6mQR2KL26cE/VYJvMi3qSoYqRiyk/XukvYF4nTz8VLbuL9GhM58E+g0KMxsykyvBFZLWbt8UHsTt1mXxSmU6M7jPxV5WeGnwR6pQy75h5oWs3E5XoFFwdGX+zSSXxPyoO/z9g1YAZ0UHMBKesI2kEdJc0pYN7Pk1fhjlD+1MZxpb2rWjkHpJp7LuOPsWpW5ylMnbRTkPpJ8unjVKgo3gFCLwZLh2tFL7jknOYBt181zY4E+FKnglG2Xn/aLYx1Vj01OFMm4/c0RkeazHf6KhhDRMHlW/L1XkrC8ZHuUhftAowuE5x+L1KISaiz/SgbbUbebzUkCmB+5L3Srplyld6R90+FW564WgrhhkB5bVks4I9f2h4sOEM95XoL2tZjoSpVn5s+4/gzQSndA4nTqRepoheUU8ExQyPjMztV8ed9q1U8R+nxUge0r1KKBHIXxSMQhkKHtb4oqEAtrMatnNEATuk8WihyLdbL5ohdJsE+aZh6g2611hwr+xUBaGLkmxJdOtAmIDIDyc9GoAHMTL/tCL93D1LWaBwk970owGZYWh8W6SfDWMdAA80BCdRN+elQXneQvF6MvFylfBSYdoDppFqkSgbJaU2TlC/docLA8uOw1iQXWAHN4mgYQdpbcafoq9ztklJpM2mpi69VinRBM2GGN6jwVm8x4iZqwJI3s94ouB04AEe8UjHSInO99aMmhmXxa1T6icET2JY7UUxnNxnzPekEzoYlkfNLcA5+JScmcZs4lZpvEWZSV8q96286Oe1qPJB6IeZoE+dPYfaltIYLJHeaHMT20ur5KPN85ZADriiZYM5ZdrtJ4EYAI/33TcqCqpQHxTn0ToN+sU0JdxCO2f21EuZcs/3emMO3SUwseblKVdINJxxmKwzDEpRzeiL+KN/xCDpj5ptmTEfe1SXc7in3T2I2+hVkidGU+QoCSndEe/mjsiB2F6Qw0OEFHdRewI4vvr2p+VcBJHSaxjBpIXfPOlIkAndGfNJeQP5fVY/vKfU08sf6xin+p260r6B960m2TwM7Yo5gu/2gsUhc3p9qbboFb81oh2adNsdaQsZvK6mA/ZoJZziUO7KeqFuN6KW6kULIrxFl+r0ttLbycdKagSzi2nb5qJKmGJ0oHsYvU6MgEXk3ca1lxyUXPZBbpMzRcjwKVpuxNjuU4fIw11qGUNhg9b1ng6tArA7GDqCah32oRdwX3TKFurEjq70Qv8GztLWQ+Tb+G1FozdUj5vSchO8Kn0aVjeWJ8tqihOYrH1TnwD51qdieJ6xNDKwNwAeHHimV1Cbi/wDIpqyV4Ysx1IaO2ENHLua1rTWLKnaA63ptSLkk/XzmlhvQLd8l7UPMGi2OGZx0q+BDUi28yVaoDMs/b8V4IAva9Gs3lgntmoxHzBJ/h1d6jyIv7FLPqrVCagIvmD1i1SQI3DohAipqa28q3qVAhu+34qODYWsKX73qc3M31O03PdLLBtE+aiJF2i3j+04ADcIfVqlFyhJYGyVo5eWTvFWoI0sFu5NIY7KM8VIsHQmhdcmgjHqtk9n+UkZuxHyNPZ7Go9pdVpRCY8sDu3GIptd1Ux4/s1HiKNU+2hlDoChtLzd8Veww/iz/AGlES5uOf3ekl2upd2sWogApqpPeB7oubW6R4VpiA95cO8adauhXLAx5+2hXDuDfE0H7LHiooJnKV2YKWhd4H45pvMi83fcvxTaRZkUfNa4BNtI5Y0oyoN3L92mTb+m+9SpdrBKfVace9h3ijFoNgE8fdZAPdX39U8TBqUkPCum9Ro7h8CJ8NDtzqKgzA2A+LvmlwX3i9S5fQWabmfb8mi3eiH+RQc3ze5W5iQrWwDj7CKBZ8VrzFQNRpB/eKIXptojxGaxDqy9lMbtEonoKGTJN7T0t/aPSgWjnxBRNmc3bPWaHz7MBbsT0vNNpMSyz0xWE0r3PZbh0q3H6vFOEwbWhfiIIp8+TjsTRkmrah7hBfpVoAZtcvu96uhHsyPgKyZGuR3KOjh4nvAn/ACr8qW6qXve3miDCbqwQQqjmdE0zTbmOIlI4iO7WtPZ1OG6kpS7n4Uj3Uu4AzA2zlzRcAmJMudHxTRIhsQ91vNZRJ3B/eagyozAGU72mtjOrf4q0QOImiUu6v+K3Zja36KIlzrpRswLyZpTAGMC+6xAHQKUmEWIGXmhW67emklvT+UGJxb2ba7VHsnQl+DFXiwdKfZDrZWf1NlZT1BUPdF5J8fDMdqDyO79zNa8nPpfFJWnfAWewUzQ9LR/anM7MCFQtn7t+9YSyuBn4D7oMO/N59FfdJ8NOuIaT+zWy0WL36ODpQqCY1D4n+1CJbwME7Nns1HcVxI6Wmjkj2flKtg+0EfBUWTgvcvh/aixM3sNQKELKJD6Kyw73BpIyTVb8VYrygU+qhZ/JfEUIBkrr5KfZV+D3g97SVZkO6ndkKEsZe57WooRJCSqggCfNirZa0Fm8TCC0zEkQ3JObZcjFPbIM5fH9KhXt8+dFs5rIctm0BvVmwrTU5tHmodl9H7BNqOIDVJEpDcqE/wAppYvKfJn3RGF6K0DJnacUZcneH9NYuQ9Zji0G00TIR1J/70oSAZ419UhkRGqP9aGL6C7P9rNAbpidkHNQZl21+IrexYzPyW4KSU28yqHuzfvHFBlF9PMF6JgAjBeDl5oryH6iCKBk03yft6ngmMz5VIMFXGTHSgJzud5tjimkI5gMX8vun5YnWUnUbeqiw7wT4VcRX024OlOLo/p0q8Zd7UrJPGqlMHoRV5V9hl9VpV/dJrEger/Kjyozo54vSSyOgLfSaTjqifxQ1hS15PMUpLMa3HSIiljY2ib8XxWCgO6jpFHltUm/ZUoqArWAT0Jt0qVExyX8xTWgDVlh+Y80in8Jt90AFEcOjjGetAJZFpT5fVMYHZl8n3WALfu953qVmRzYoO5PBKLjjnSrUNSzfpafimHNNh+X+lOyxxoYfNRspjECXkZ70PbuB829VLD2YjpEeqLubt7gDND3HhZT7j1SUELqD0KFyNuWOVoi5RcLeAotmOMh7K1nC7G3eHFXiEbljuBHmmwU2GfioPoUP9oTEiQEK+2InpV7YXvN3m9MoCvEe6ACDyy7zegRPcQo8pt4vhq9xc2VfTVnINR8mj3kdeaGsHiZ+pqNNvT/ALijkETEgnup6nvS2OlFI3YbUHXmJ1u6UVDjQYtpe7sUVbT1fm9KwlNJnGkStBiB0WqCszAyLPF58UNY7QTE9LzbwTUCXm0Kb6gLSyKvCsQeZFD1VlIYQXfv1qDLiNbx3j4qKDiNQ9p0qSLw0f7T1WfD4LTxFnzRS3bxZTtbXpRAwHBN45Jn3UDEsLltjPc81jGDQHnRik+rks9ptPhaSYdtFHeVehhvbBMvxNOtyImHaJ7jR9qAD4CguCQgqBgITyNNfdcmerFFwQO8rfFKxJ3AM+qTgQ3JcRapEqS8MhVkcv2avZo0u1q91di/H+VbO4PuaCWCOwfynrwus3rOH9nSttvflvWKQLcW608ERMPG2agOSyWQ7l6ViRjE5O4w+KVQici/2t2Sb2/lJEkG5PVYAbsh9lSIE9VvAFQSkeA/2r+XlY92oGcwgu9VgVwQDrlp4bonbXQ05ZHl/JphIS8JxwZexVvffiBtpMeKZR0xOINZGZ9UlI5anqE8NTAEb/ooOVcsv/KAQ28bu+CayEsRMj6oulTa8dJxWuUagDzR5Ydbe9WCNuMHxFKKJ5w/2psqdbqG5eL1KYVZm0r7qDCR7vNAJQZvY9U+0b0mKufaQjwTNa2HUX3QmNpF0+KZSAcC9r9audyN8+Ep+HwD0detFUMt0p6brxQQKBpYgxMoicTh0W1CiMMJWySvdWyUxAnoKSmbqTl8SiiRbjujOwOM361C4m0CyjMQw9aXMCUQxlaWTGk2ylShGsHYMIc855gLNIzOmdLiSTSRuLXaZLISVxQwKSYETAIMok1cQuEX0p3HUibKRiLeZIEjhlvyD0pYOjXccgHTWrMO4Y6S+4om7IgIvqq9R4oRbjxKc7URhAa7G1pZtN4pKGS8pYB3gfHmokqWVBL2sURcQWsj1tRlGxvlpBtCaB+80kibBbd7RTLB1CcUk8IGKAXJtMTrOvQq6lGIIyYliNac2PK593ouWZsTPiaXe4ZWjvp5pTY9yPdCnVQPspWVBsI9NM9kfZoe0Zzbrlpi5ToqUAZOI/FAw+WKeLiLTSKZJtrUFnUWFmOktEpJjQQW0vWyDeUvS0UFm2QvAPzUBBMEqdr0vYJtJd7p8vysnyi3oqNYF8Se6QuuDL2I80TW6cCk9ZigYhnW9/OfdYghyY8XrIigyHqde1DshjcOw1pGOBfn6pnAHaSdrWprV1E+qU2S8E/VAkA5ll+lGnA2hV9R4Uz5qLPMIY0iGiWV1gr4rEd9mPFHJLgWeLutEWA2nUgsUu5GiJ6xUQiY3vP7pVgvbE/2lrqO61EKZoHuWie9NsnS1GOmbxSN5jg+4oW1+LI+wqVEDi5dGHapgkdU/YHaiEBZCJeUeTHeiuEq6ouyq9M0QwmWEENIAlniH0wXOg2XFAd6BYUGaBOIJTKBEmpHEYALVBlG1+3aaYJAs2Uzt/RJjFHHK1+XWjMltTqRc8UaUK3LgwQULkCkkCtiCYIBRQKhJWRM1ey2RdkLX1k3wyFCy84C0u1jRLsMSHYuKeKWnYBWTnJHOo9qswhuSnuxZ4paCSxLL9HWmBc3sc936KuWx1s35UmpxEQxYuIatCqcTPcmrIDkSPI0kyIzKMd5J7U74F56S1sS3WIOBL5qJCtwcdnKkqBuG841B7UMsPAAviJo0hLF5u2pMQ2aTPW16Yzefl3KBmQ6VHSBoB80MR309r0XW6h/Km3EcAnxQl++BWgK6kBWGF6RIPPTqfNYQ7IJR/tXoLvFnbo1LlJ6h+qwT3lbQuMev5Ud3nWqUNAYsn+VOMcUn22pNphOk+tKW6r5/tE8y4mDjS9XAZ2mPVAjUMMOlrusXjaowF4ZP5WZimMP0nqiLzdEPCzSMj6vnenZGTyHaaFgg5TqopR8Lef29Rgz5T7SrIDlj/b1rI4mFv3+qZvlgLHalxcG6/2mvZskmpOBuYse6SFbhma+It5qxNOLT6muW9Lnn/Ku0cLQn1WODvHzpSy6eX7ijTL8v7QzWYvRgSw1lD1enLszaZH7rUjITG6c8r0zeiLpZmbPGWOqdKG0RIC8F+0gKY9KwwMliQqFgi4QlqcIQkXKAjM7ktrGZ4iHEiPVJqXLTG96SNlxzscnhdANmaFCQjfzf4SiqAgVYJeBCsuOFubQmEgSQAyEPoJz0ijVgl5ZZZuQOzOKmysTdB1LDC3wPFAXYMD31PFLmqCZADtDkc3oO6BnDxM2ebUASpFmFv0vigxLGui+6tsPJ/lSYROLy97VZ9qvTC2o1CSHN5tvR6lV4xZ0nD7oGzuggC947rxVgt0xJT56wRTFgnlvPM3oRxubrD3tRi16JaNcmRvtRrys3mNOk0/H2J61jJG0f5TtkHTemwcax/KA39XomxFAkgJ3/ZpyD2qYV9Ik+2Kz9b/K1YJNLfvmnZeA170oFRvbZ9z2pmQDgW9/NNsfJHsozz8f5QsnqcaaUsYCbRRKsiaWifWOlcIXzQwmSd4Pm9aIZtLdzixOs1kLRoQ+6Mt2Aie8wVYyHxT1/TRbh1IwOjF6d1xyY8zRGz6F/wCVpgNiX7PilGQ+fddKAbdZP9aGWW7tq1vjl+atYSxFh6rTFmZT/tFoia2us/yKlEAeCPFBJBaYT+X90Vl/Q/mpE8u/xmolZ7xPmxWArkXmWjrDeQnn6oW1WL4cS5OjTRLG0hv1Iv1oF2BoJgZtMncoaYICnRqw/VGOIyRkb25gNKxFCCoShYY0DgwIsqUmuJJGkEoCZyErHioACK2mF5gloKeAxYSQJRqkCZtV/S6BEYOAyIjtHNZPJbo5HDaRizmtOzi/XipGEymCbvWRZ92kwRDmSwTfi7pLYWQvUJrFOLYzE3QysheUqwa63wNRSBNU7ypcfCKAOWSlmEMWoPNgTMCMgRvzX0QlfqjHFDM9pnPSKS1XOU9NilYC/Y/2ncH6kkc6vFA7d1QTzak4EdyY/naoqxHcP3zUURHiWOoKiSUH6vpV+si4Ele0Rf1TlUTzKznmjrnWPb+0s2Xpee96snfFO+GD8VG09ZadbY71ChDERDyzVwu7EfNSIBE9XzQASuIKQAlhp7tTE32zimLE5rD5z8VqekY+YqRMHK2pd3pCWoAIY4T2mtMkNIPeYelEWU7IJHfXiKBwneDrc04RpiVcMAWXWXxQzfitHldpAYB4L+UnxUm4Xm8cysFYZ+FB5sq6FLWVPu1QAxyTYjcvWYkbmPt9UoBC0g7rleWmEhbqgeVKyiXkKeLe6B6vBPgVobCWsA8l+quso0FfAPKUzDu9x5X3YoBkS8iXFoUEzW6fvjVqUtIXyvmmERM2wtYiLwNNXJ6PWrPE3P7T7JWu4VHkq6pjufZVqMdVh+IauUDqPwKQ9+AnqStqZJpuh4AXoTUJlTmynWNOSj21E+fhqIZCOqbZM2QqbwjuVAIHDylgG9nc3U4oCkXDDgRBsdcUpIkwxaCw5b2I+LJKJGSXenHWpxyJbJGt/SToGEWIFg4ZQS8TKgJd3okFDFkHqlkAhMoGKQu7Dj4pCE7sAJgIbATG1OUiEiLhmOgXztQdD6Ba5v4YstimQNCy52xqZgqAgKQF6AcRBdDcJokQJITEnNMJlMO5XQGG7aHZuzJzamRepY9GepQ5AC6au5Ye5aeIhyzJIZmRAeKTR9VVE7/5SQuwxZ24tJGtEXGDWIe+SlJZEdJpUo7lIY/5TbXja5dRMHM07ZHlNOSW+6Xp+8hrLD4oIUUXnPmKmrG44303oh6lMFtuQPExPaaUy3+vBPumhDNd/Vq1QNbZ9xUSZG83ojLquEcrdpSQcJoS/wCOkeL0m3BYv/KZeXoJ/lRohDBKGM7fFRV+tn/KZgByqFujenMkNDZyzFKYg8gvxFBNCbQ/lOkDG0owVEm5GJBxOKBhTDlPnFacZDF9j8NY/wAxGHu5hEhgSdtywksATZMqBIpDXwkH2T8UNKci+16ebujhW/61DsDFlXXYt5oCecA9Hy1ABMm9me9SoiZ7VPlBsJY5aSIFbxBPmaUrrj+1doRlRjvTSDQbT4lKLlIpkonIZ1GW3alhOxIcpOpmNaXkRKSK4s3jJiBogROeo07YPr/lR0QNiE8zSQOOof7TpiIDIcKCNd8UCwFECZQcA569qsrihZjuIfFYehBMbFpiQXQmM7VZMJIFlOzkV0Cgc1dPdmc5ldFmTbTSpigGMltABm6TJqqmRCbQZ/nJicUsixCiuhQGQMJCXDYoJiIQLMlk2ajDMoqQ8sjKawszQZGEclI2DXN363LgxgBwnRsqyQVlumMxIXC71vRolBACREBAF1WbsWKFboYmWhBMNIzTA5DLAkTCrstEJmV1byRdUxDAvE4yEBmKVuQuJsNIGRlhc76Vdz2bJ7hFAsochAPdqRPUQAYuNp83oCBnDI33sKScuaOikL6LnW03OtQswRCEScikxuR3inEU5liOs/2jIJJlZfRamxJSigjxCaUVgYMXt6i/GOKVWjUiZ/cVbjEyAl9S0h4oskSBkkxyIo0BkjrZ6HkoBbaWQOEDZ6U5dI3j4kit3NpMd/uoExAg86/8pZZGJp2a9GmWOGEn7pWmY1tr/wA4rKu6TWYHn+mp0Wc6h4sFDQx97vrUghlkbTV8F7JfrJT0p3X+U1CmQ6XoWa9AXxpVqneSPq9NRF1oCx4qQKrESX6MVGttrLd/DsVYWSFC0TSBYmclKkTPiBJOQY67phmw1qm8Ug2CZNyq2L0ewJOaM1LQG1FF7N2e/PkO1AIXlCXQkppq9EnzB8FMEiJh4r0dRctKj1O0RqTeU0l4UoqLnAyeFL3H8MSAahZ5EQdmjrTF24wOPCw5rXX3nA4CelG1ESDBB6AHihYB0E9r1AzvCg9Yt3mgEAsUHujw8LNRg1y9iPsgzrAUgNFIza5kNst6TLcpga3mOLK60bZ5MjEzKcArMDIUzMA3lQPoVYIx8w9iGjZsxLBDfeLslMyCQyhI4iBClxl3pN7NlC1ltA4xQFixFejIR5IeLWJz+0pRMstyzgB9Ev0oSuMzGIZpwUVyArDvO/ShlaRsDmFVLrxccGrYaA3gUxdLjEh0qylwISmWrhKCoIobIAhGt5C62czVuoagVnrEZoVsFsc7zU5akYAyhfJbXKieymdES3bBMbLA8TSLvVi3n6Kbjronddj1QsrNLnrFrTABlmFEIiAMRy1zXDAIlRcNSJ6hTsQrdkhab3S8E0SFg3kATEpZL21vWgXA9xMhghtQTEbTaek2xe9qNYui56CZ6vulQhRpBR1Rmt1HGAaXvD3KvpEOHA7MNPuFmuq1IkBmwxS5gJmLqJPmY3q0kUYJk9W7UllSbtv78VmlYwauusVgABoTjffytAllrf3FIYrcUuins92ip9gu12PLSC7AvGVtMfdfxdfupoA9nv8Ayr5LO4A9lEZo6Ifi1SEAGMI7atCuh4Hga4l3UdkhagVusx8UzExbFj+0olgtxdCWfFBQVTWF3wM8d6KFJBBioQrggihEEiluASGniE2TLiWNiUpCl1onapFZBXudQEE3JUdMjlvYLXN6myLC94TAHCcG7SHNtpseKBt5tQby6/8AaTcNwj6Ed5pYroOSL6wD8FS4gEN08EJL5KfZcwrzPwa3JHEvkPijupKcRg0DtSk0ne3zQJpxcpqCaFbbWejv23oWTygy5ZUN52TJar8ZQpc611boCGCRHQCKMhBI2A+Gt4DKkcZlG+kVaXPRhZ0ii0msb63mwILNuYamMnKYkUXpPzUl1zXpRAlxYJHFDRNOP5vJ9FAt6kgRnTomq0YSkiJJXJO0gwxDLTiEJJi+giLyMQvfpBSESybFgXtmpwIK7gUuauYAfR6TFBjdRMjjQya2HagpqWE6mBBBS8TVvai2CYt2Tbm+zSmTBi5DnTRpCVNBiWyYKLcCEkhK4uhIiCkBmpJMImzoeSiIndQROYhQiEG+dFBBKCJIBgvoEyfVEUs4QOV2MwsWKuAyEYEMWGG2VhxGKgRoWcr9zShZTASlfakFIFchXXmQDZmhLVxmBLwSwnJzQBiDCXEuaJHirVFoGVGbpbYhHWJyVwiEYJizF2I1VKmQdopZOJzeF+HeiZZYb9LWfNJ1RK6EOQYmd9dKt3ShADzdFuSObVNZBMyqOylu5QtwGkQJ65fNAyidJV7u9SQJIyL9jUnXM338HzRcM6Jisnjq38VkSeZSOKTZ2yi+3Sr3V1bvT7pe0naJv9dqAMAv0KIxINU14mkbtcAWPFNAJtKBtBWMLtP1xQwQlxKBMMoiMzvQJaAPkAttIWB3MylrL2orYhYJYjESPWQ0fano41TW5o04OAnyz81elUbyy5tNg69qj1U5w7W+lBDPgg96Hec90rEEXt/cs+aJ01491YAgnzRRXgqHGe/qkSxjmi2dQKtf9PMU2w8n/LUTp8UH9/mKdt49TT+AlRdbAmUpzJLKUE4SbEsjLF892IBRrBPWeuKIuwATCIOjl0mwiKBhoQv0Eb3z2qzS4pxG3dQNFujUVsTaxbiGoTTLG62JuTYHMSEERVS44CCDHBCZikgWVBlTickpi4ONaiJiptgpkouGEtHxtTXYpZnsMnUjPXFSwETPVWxc6XqSDSj0ZABDCkhM3mrApeZKxZiGRGgX+KnjKClhgSDdAoDcjRiGVCAbAiDgUxy3VmaSlINraiIkkDYGeaVgnmUHYzePZS8DpggOhYi2JUScNMVgFi5tkQes5TFAboYkCPRmdKiqSH60lwjs+aWCWuQ3wN6t4vBJF5NN/FYnC4JRDOV9JKIKySzFiWGL5QgplMJoB0N5vm9qMDdCESAm9tR2ajlS9kAFREvcmKuyAzDZ4oYQPOs02IxM4Mp0mX3XZk3V6f6ozJnTTTYoSCS5oDWWxP8AyhguJgcjliTZrIE2l9RT2r3+6wtziKnsflu0Pd1Cwj09q1i8kvzU4j3j+0qlBuYfMr1q9poHid30ohYNUMD0UISg0kOpaoTH4yeRinwtNow+jtFRl7tYMHa9XUhygQZi2THajbQwLNxI7z6mmUMOto4EBAuUyyiZ+xTE3SbguTqb8C/Whs4L2v0ShGJ/3miWbuKnAOZ5qHfeheiXanFLsdrff3Xb9/8AOlYPr/3vCadviuOotdf00s5xejPkkQg9iNm8OjQoJZZlVhAQXMAbCKTp5ESrBSMJCCUhS0CS7B0AzrNfaj+PmrGgGNGoW8GaCBJAhRa8ApCAWhBEvRwVWmCWPGCaFmKhVmSIKRJAl4yiKyNqgmwyhFSw1EZHkPersQKhUYDwF7CpCUiwCXGAtkrLZLLIH5uXoRPVJQ5iE+KgGWkza7ozFNY3VFHXK06fNTN4hextvaKQYhDqHxes1QcXv061OJV0mSHEQ96i6N1BbWzCtp3FqLC4EAoRKAgx171tBwtAxfsDSKOSsm0RwKLBsBRSSREkRRdtCYnSanNbASjSIzZqJUQEK6YeX+96yTwDLCyaMMi9KjSMQJkdH/OaVmwRrjxVsLnouzzV2BZMXejiaeY8XZoHlaISa6mou6xHaaNcJGBL5JcjJJxV2ulZHUFT27paWW/zTJ/afW/BRXCbp7xWYVsS0v7NZLvSJ8UzLnFvnFDmSBgyugTRpmdoFXoCOj+E+aHdSxJL1Nut6GAG42/XppeYyv7nxU3J6Oj0ogSYCSTlEDudaZt3cR+gKzBqWHKVQ9Ib3Eb1KoQDnFdSThSQcEgkKVBhEDqDCI2RPNNSYG4MdZmicgWAxLWCxETYpVe0W81z71b81+P+xVj9NLmLb/8Ajjo/G9vmtmh/5H/qn7FTCZERHCJCJrI03M+N9ptuJzQzYEiBeBAl5SOWrblsudzKXKNWVY1FStmYmcyES7lWqn/yOVMUAsMwW5BpjUZ/dfqgumRJpwi+7j9GKnCMEbUjDXhAEkWQs2JJBalIMEkglhi0P1StnhU9gX77U2OoGFu7RkrluFh0sOp3oldE1kNgA4XOkUwyUxYNnquOIo0KiCYXA20WNPCryAvGEz2vRhGHJEsGgJCa3npQWMhiAQuwElJMhOgZne8j7KtoERZwL3U13A0o4xsJG1gwJjKqjgEkG8bpcQXRtmmQFibhImSRki/SiiCDZbADM7W/TWAaZwrFk0NZi+9OxEpYW4zdCDrehQShhtI9yjEyiGBCJ8UoCi5OqOqW6NKxEXFjNvfUqwmGGQvqs47UhBANQksWQVe4JZqwcMByHDJmsmDqwDRs6lMkqwidJfd61M8BB0xQEGHCHy3oTdGwnzei4Idt/miDLm0Hb8VLuoRgPLf4xQVgHa3+1N4jmZjw/NJZkDBDH84mjZdFiU9qeqMRB0In6rXQ4n/YpCUZNT4VfBT1oDpOyvNOSWReDCReZIbZmbVCy8RcADLtFkWpFspCKoXziSV6cc81AADYJg2bPTD/ALRzFrIiC7DXzTBINMDnYTmL8VbvvBnw/ihti+2j0zfrTohN+Ojr3qY3P2aLJY+H+Up19xpG/Wly3Hx0vX/D/wCbJKGip6Pv6hLF9BK68FMkhEURyRaHkdNGls1A5vB6OrZxUIC4J6sE/NfB++qaCbXoBEBjARrQGwm5dQWviO1DwOUcfuSk3uNoPopa44pNEYO5JemOU6TD0msko0n9Y9VGavKX4oq7fSJfmkgdJcL96LEzGAYOx6pmF1doQ5Yt1NQkSAyG67mVhYj+Uy2ALCss30QlagIRwU4mzHtqe0oXRhPLLwUNC9rFpRiZtzEa1dgTKSk4Fz0CKDcDcakXRHDWEKwlCRWbzrExxBpThpnANiwHtvRm48MY2tiDpTogQiIgMQbSPW3FHqzEhgrE5SL6x1L1IFbzGGovcYZI1UF7BvIBuQXxpQI3JLEIwgGC2KEQLKANkujhu2tTmCZ1F2o5KESQaJD4pjS3DvGtWR01ce/5QvkEV6A8lJXANgCo+U8Kurx8/NO1dFf7QxVGyLxNv7Rft6MtIpMLOtD4loWlFOBwEh8NM0vVaB65q6KHTP8AZpBbgnoX0Di9LCJDCCgGQIkIgkYis2BYCAzisGEQ3lJKISdjEHYVAVC6B0ajZrYlhjYZjm/RxQx2gazgsks5mZvPDU/sTKluSCx8tMI53Wk9nopNb1H3VjH/AIYX7NGOjnvXQ/b71h/dTqf84/8AShU1HT0e6mESI1+AZnQvIIXac97sIuIBHUTy07HIP990aKOImIMgbwoI2kLKlAZYTc7y+qL2vOaQkEXPLQbEo+H5oD+ifCzU0BKyIbG14hM9qUi+PNCx0pfqlv7fdRSWHk+5pDJ1Nf8AKfK5N28On/agg8lFV3sFQIWSZhBB7RTGBkY+cbGLUhE6oweSiAmALLLejMRSzXvgmUyvKLKZ28ihYQkOET0HntRKyE0C0GpBUIiy11i/F5dsUiMD1id7c2xTzh8W4604iIbQnQCMDeSos7yJeof21yLU5Cki3OWWQKM3L95qyQnQJkdbuy4otKUluYhEUR2lqWxG6AHGbD3ikwZ6xj3TMBvY5rbvq/2kclM70XK70QWDsE/L7oGAHRbvept4ej8UC6Pip7LstF1BiCT+UI1l13ofE0wlXtqlGbiCARqmSJqFzg0akWLMc0u/uk0PqN7PqlBBDYCRCyXGmJNylfgb1eF4MBt5plrGr/v8roxjtTs44A4i9GG5aS1BRtYxcUJYhsKA8SiWhpYusIgmETH2ulpijlYTYavM1cE2i1ptrvOe9GOkf7/4mvXR/wCUvq504/8ACagofPv/ACgpH79NQkArQyuV3iM5u71AbIjtp7zQt/4bPT+1GLCgoT3McY1XFaEHTD1makQMjVl+KK3f161Cm01uhza9pbeKs2G/G2cFQLunbej0F9fqhYZPKXOKZLdbFhOjrGzTjCSaMfcUxZm2377pM2YciaVmrhzAxp2eas2kGBJOmzN5vrvVysuQJQRFZCCCwQxUhcIiSsOojNt40qRM9Qbl8qRHe9BpG67UaTKnGaGjZMl0DpCPzFqSAEkkmx6xSgcy4hJudptwlDsESIsKQJnM6dqRhE0xY7EcOKesygnIb8ZlO2bU/mWFjg1JTsiOWkAKiBFxqzclexvmplSItyG4moAW5pAg/eUozBjmFfAFS3mP3qlLp4L+a2B9U6jt28707h1qyAHgv7a2twf4VYXnew7b+KwLIrR4OaU61JpqlhQZNXxKO6fVBEAhyTC2l1GwsY2KnrgsXA0kBjsvWnrMG5J8nop5sHZU96KgsG8F3tigRjMyyRji2nNTgRsJuOkzhpQgnSwEnUyZGI3GBhJcjl2yMvIgmTUpgqGM3zVqy1JLP+0SYjPeooaUSUgTxV56/wDnJ/8AC5b81E9v/AKFBU9QHH/kimJAVyACqmwAKrajR7uEXKDQDFuZXtS8xz++qL6aRba2q1m7YFIXH9KWRfQ4mgPu37pU5JqUhq/vjtTpCpyz8tBSGe9jPmrkCLk08Uycnx/lBJEl1SY4iTzTg3YOAxBTk4DMZi+EDEYqwESxJIETrMmcX0qUgIWVtl3c+oqFFxgTDquV0J5qQlQbcX1vWQVsSXZxaLfVK23EQHl1GLW2xUxalhdKbo1zGNKBUHhZEic9J60ikRm6jqWcWlXu3qGqzIiUaRkjeVpxxeGezONrc1JBQWHAmyadY1pNy6H2u9cg1Lym/FXFxOZuUc31NPzTLk4zv7ps9JoIiy6M972qVIvxp1fq9cI+al08tByOhTH9qLF6V0p2jWAAwAvb5A11qSUBUrJa1nU2i0Ygii3pYgc0/frV8ec3g4GLvQoUGMGjvPN6J6iFJ5vIvihG5gtIixaAIWcyVGMJUBC5AnFaSaAlWCBoYg70jdBB2aDDLoiaCAOHaTRBSCCet3QvJlTcZmXBTZzO6JvpUQFTQA6EA2UZ21Fa0FcKDRMsTtepTijJhpKYysxQRbk72ifV6B/5/lQJgltLZXb/ACnkTRBGYWQmTQG7SgZs/p7UUdbUG9t9KGaDeodamCCZUB1WAroKxpmJHRtRTfSClq0pteIjt7tP7nFwKsLRiske8yETqRFkWQZEtCK71FYRtmIX+FaEgZtammIxsVfLOlWBbbcVNrP1TBv5j/akIebR8UhpZ4/qglJvSm6OhFEWYtp/tQ+4061cHPShSlzzYu+qDF4zEXH+UO3hv2p0Sj9pRMSMXKdd7J/FMSEQ21fmmAir3wbqxNS35bsrt9p7UsKokRcWzCvjSUrW2elXMDG5+K1iG9tVOkI8H+FrFNyjadsB3LVMiEsSv3vUKc6we6hcIagHleOlDvMjPda9KdWJhmxr1W7TjRjb9rUrCmmA6sVr081v0XLOxQWS/u1EsRzFOmETZBiTbeOKWz7zRVE0FYY7zWqP+VM4Wikxlnjbh1mnAacgbRyq7UKnCtOXrA5KkBFnSYDfz7pYbjMStAFdYfVFGI2FiXo2b6U0xAOEBFeiRjh8VagCxkDtI+YW5oSURGLEtuZ6g1Il4nACDYnHTH8MI3EPS27a2ZatgQW0eTIX1s0UCyKhB1WD6Ky4mnBGSoyFZUGQWLoXq45obtDIpyz2yYJJENwSZJW7udeaS4iLJYGJRvGxujXNAMGyoGrZVQtoNbRSjCFAhUL7k7UBhHAnr4J+klDSpO6l7se6ViZixMNthtB6pBF7Gk/78UZHRLIXOSYgDc6YcLJVyq2yqz0nNDZ1uTtSovZttJsm3WgOLstrdAxV4w254o5jqUETrsX+L+qu7REGPmiGQY8zR1EtSoiCLW9UjS9IzFD380kCSNFsscFr96vLfq2e8W7U0gMzjPN9KXEd2oy8EUDW9NWSzeb35q7nG/1QpKt0IbItkji1SiYRelHC2hzjNYwx+87TGWNR9VK552a2UcO9XYe3U0tv+Sp+W8MTvKnoqTEidO3DF/FNmMrrM9aYBS1kK8K24IakCMzMSV+R0ikML3F+LUcTb5b0K3JOw8tPsI8D5oVlK961LFBlmaFzxToW81aS/FEJQcWvViGaB/eqdWK2X7xWQj4q/YGaERI6Y761abCRqXiRzPEc1hbPFTgvhEMWO1JctmF5+6YZk50J4jE0RiECJSTpe1tJvHarQAuSAiakz0kc53ARFy/0hvaQY2aMXivA0WskdB0VdY5FLJrPDUxLimwniHszxXMDJEDzJ6UBlYNweoHqhare6PeT605XsdAACEflmptPpHsCsFKbQAe2eWi8obKHmgimTF5wlzFx55qEENof7YokBljGZeb1jhd8eKegEAlYqQyoQaA9Vjuy1n/tOJZC9qEiIHdaUso97/ootpnfmm2CcGe9bH+0d5GvajYV6f8AiUGo6anJTZh9TTcHE/5UGUve16MqPloWy9CgEA5a+qb9NJlB2/Wpu3rI0xQTW0T2q/mkZiG2rD6/tDSeqZm+038UScSD6lpO1mo9CWjNuSE67VLP2GlNHTTPetcKeR927Kllzsv8Xp1iBux/tTrC2Av1UYl0xEvSxFMGFSW4YcNnpWYw7vqaiIJ5f3NOewd6TL1WIJnmrZ4bda0ajcmP7QKQfNJyxgNWULvC5irRK+aVXn3NBSqpFovGrbNOIOC16gK3TFGKGNRr706UhTTilnl3qPjzR9zo3+ZpaSjG4t4KyBYXZX/r/aOE2PzNIp3UlQY8EDtgoFmjKBvuJJjRT3SZWApQe42ltNrpRUDulWLDMbtjuUjIqECTAgHGBjpUUDcLA8rL1o24hBjl1lc5nvQ4o0ORi+BxNqij6BJ0SQZ4rQSd6tYxrG9Ajn9mksnS0H3NZosGpe4KdGJhiuasQtosLyiYvI8Sejqt4emm37NLQ4sgIWQVZzfcQQUUMyXfrfvTay6cFNdDa4IB3OKm3QNi7/ApOV0p8TH7mjgcsX3mX6qbWB5pXVe8eShzr109tWoWZ5sf7W0ltP5SoQk6m1PNXTFDT5GhMMcC+2hOHuNL09UOmyfFPN8Uqga/v2lKw74Ne3HWkK8NeZ/7SWB2X010zV8sN9Va46zSKSEzCW/7URYYkI+ptPDMUTAJ3gH1V8G8Evly81O1Hf4KQTZsXn4qcsCyRAsd8UF5dfx/KuDM96mkjqv8UIIQ4BbfMz3osX8RFOgJVW0REftaQ1Z6XP8AKFSUdZP5HuirKO4hPSC9X9pTK61FYEUo4HQv5pRBEO1OyS8D87UEzF5mY3wS6FMCS6ry9YtJUS6XFoec0bE+WLbzSczRNTTh7UmPqpXrxRTGXbTvxTOGWxa3ir9WNhheJzikEQMyiB1VeoimM3dwdIsIdKkMw3uzfzNlILJGETgxeJnmsWKuYJwgDq27FSrO4SPMr1igZY2QW1mAAb3Y0omFdb2n+01iy0lCeVQOq1jhYzEOOje+Es1qA7UfMhpLA/50KOCwiF7NmU7tsZijCxTF3Ze90keM0goCCxBlDVaSbo0qNl+6rGvFTMkcztp7mm7IF+b2xvT3ZGy3QsX1i/GXmi1B6j00pHDbZ/tqmmUjCOHnM+a0QHtelvZnk9ZoNiptPihvFnrb5qdeHpsa9XfWjMx3pRaJ6XmtTcQ/elW4kom0McUQWQGik+mhFtPJh9/FNcHef+UFgHnfNTkQM4MJD782qEJN0cx0cUBprQDGwM2pJliMEM8mnkuYl4dKlhWVnZ/NYrlCbC2G6BMnbagD2WwbKFr2IjHirgo4iVQMnfT3M1jujLA7zxTqqzMFikGfmp8sXoNEpG4WcMtd3FLL4NbA7v1Roi2gHZq9TQq7QkQHSMWtvzQTfCLseO9M5BwVBEMUkS63mpca1rP6bVYmI5z8X9VKWgbsieVp9we6eK36it7/ALVjKmInNCwNYeb/AMmrgBexJccDwJvTTBd12VBs/M1BYm2zH3Vmz3H0x90hKrGHXrOO1TadHktd4tq0mICGb6j3/wC1ClYItNl4M/VGQmNss8087hxItmzDc60oyhmWfd6QXHDrHgp259UYFQouWnGYDiicl1un3pS5QUxqwLbrBahoCbsH9X4oGUDNlwzN2i7LelSmSVW6rdWoK05jF+58TNMEy2d2MdZo0FxOSOTWosmN/wDpQ9K0C/J3rfG3EtCmMETRa60LQwteJTu/VIxCki1404oGLc5qHmeulPB7/sUs3Tgt8aU7xC8QzT8C/Wf5UTbf/tEIh/fFFZthaks3JsUjht2XqZIeFBOQZhhbHsjzV3QnSMnWU7lGsQ3N9r0BkKPzzpmiWkiHCzxrO5amuTjwBMd6RXVznSjNNs044TibUgwDF0ha3WiGSJQMzu4ZMRVss0EfK2Veh0tUmWzRZ91kLUwZvWJdMQk+KRLYTMIz2Yp4mXgFtgzRmQtu38fVWMJPmp7f6Ui3Xnmk0mOtK5qykaQb4LjjrU4QCLXYjni7NETITcLKbAz1mrcfuZ1oBNN+66bVBr/v1TIksWg6Xv8A5FK6vumCVZGzAf8APFJFmWcZe6XX2fpoXSJ1OaHV/aUFr8ltqjRf+vO9QawddaikxOtFBBbA2IjVMMN71M2iSEICbdaeheLB1nNGdl38VAlZN4zpaumIwl3rtxRJCW2bj2bVJBAwvMxfSZY4KgY2pG3i1dTzYppz0opEjohIvJM+qkQ2jXRrcZ5/lCxbqxi9PGbOMlTHN/il2PETUg2Mafu9AjRHca2ib3CP3WlZYOKILT1b0x2Jpz5TUaGZyRMH1TDc5Ke4BWc7cc1bwkv16BszQhdJyXjhDieGjR5mE770YIADeJvojsbzUbI5TfgRs8alIgKkuv0futFbliikHf8AYSnaKQSWd9qGuHxUjCLaXnbbrSLIXManhqaIDoBF27AW5oVaNy9+k3aBszSZIOxmrMJkREAt4+6c1vuUQBa0q4veevBRFVDAXEdtvmutJpfSkb4N3+UJKiqJDdiZwU54zsUIiDwjQswnH/P/AC3ca1EsJiy6UgLKNy5Wiwa4/laSwtjzUDOaTcFilknfEfooSAObP5TAJQysuhppUvHeawj92pyO2KVZjGKTU+6VoPut0k5qymHHXXtRtdLDGQiY5GWgjFVkyLfBljVIpFbWciGiZlXjYzelVlhdTBIA7Wc6GNaNWQOJR6hpmbPecd6MsQssGLhabLfWpgpqihZpZQBtD6ri21mbdM2qLL6qCt1qxA9S0RaUSHE2jrUaM7WLO1l8/FN5iUnfUv0tHFFPYUkjTinSbN3E8b1ytm3iWlokAZ3ilLkl5ozl68a0BKw7BRbU0T7NOjRMBSzEJzpHSgpn6oW0SXu741vU/HxQ3BVtMSb4/nmhcxumn7pQVmW8fxm1GMF+/l0oR07Vj+vRzSYTM6JUGUMBhZ3ipSUJoMw7KWmsn5puY6UqICDXPim5oYOCSdKEwiYzQF0LhuwxeYl7NFi8AIDjNoNKOS3gsPX7xQQPVwdg1zVt28tuetM5YnUcRoH+U3EsJFwE6XlioiJAxNpXtnp7oAvlggAc2XXSXfii5gdouNZgLaxRYRkyN/8AloohMcQYvvvUDRrx0rRihF0GePFip1HQtvV7daGQH3WqE4iiyjm2aiEA1Wm2CdLNDoibl7waNG1PH9oBi7fSkGWF5rpUru5rSerVJYek1CW6w0TjcAb5xe2h91ljeymaMjqfSWb1k6WoVk4whlY0S/GukmKGYoYAFE5kAXvij4V0v+91cDiGTEEN7oTx0qQKylmTcTBu3KSw3iIvLvSMms2+63n88/VR2SYZ0Y4069qY577/ADSpGjBEZ1601oa7XjlU6EsF75L4nNKl8HtKdD4RaKW0aUhDqnjTTzW6+70TNzF79uN5o1x6oE2pGzPSkbh6x1ohvd9Hag1l0oHFusVEu/VAXUPzSXv7zSlLIaoSd62GzbH+VM3H9uJR4RYzvHOHzUQhZvJu1Zy0uU2oL6zetRf1RGCmLfeIlHtRmXU2+JzxWStxMedHapHNc7Qte5mdsKTNRWCGUzLeC5kpyArvIIRiXQF2fdORuAiY7fOlADKCE2Xzkd+tLSQBJFzliwppd81ApWsU63lqGSTgncYKO+IvbB/3zSUliLZxbHLsURBgnQ2N9S7FihmwxF3Vd3riNKRe4pe8U5WnPtm9K0D9xSus9D7igsshtP20DhFxNr0wzL7rAWE0/wBtPaka/uetM5TYWaHQz3wd6uyER+ipITCyBxu1pYPbXUaD81+d6R4pMrxUjMx/Ki1XTiKiuAWAev61RizZAudf7TQ6skhXBAIaYqBni84GLJUpAMnappUpS4m4nAaFqaZL+hmDWd+PTBfYkXu87AE00GWZesFulOss74pmNVJ0kcxe22aMytGDfXi3uoQjbZiiQGVtB/v1UGEFm+jhLOxmhCAZL3tFkVOLdKwoFF8i/wC5vUZmSGG7JhSxG9REXY8xyb1Kme9BF0TQG7xxfxQxASIlb56f9qVzcnJEm87VbgDjTrUeTHe/emMI8RD8tDcR3B+qKXyfypMTffzRjrST9NM6fuKD9cpiVNS7bX06VFTJZi7E4NqDAIXLB8EfdGyjcRCe8VhTlpTMB0H205NpMRK27GfVCZcAS6rdp6gK6xK+pKUQodkQd4l7hzUS66FxexHQKTZnzY6GD0hqaM8Ak5Fgi1tB0mKBmzyCICBOVZnjO1ZUXbCsOWMtIW+qtLbZGOI1q2MnkOtpwfrYpt0pyuptDDEZxPSnJuF4GY+6c1lofTNFkkG6D+tTyVsMeMrHLVsb8/76rAJ/a1E2BzSJJi1Lb3JqBhxif+U7NgqLSaTYOlvuadJg83nprS3PYWOMbVBjSkN5qXLRf9/8MwWrodiLH9p1/XpvTmnBGHJ4ycmptRkmwCysYNb8VLEA2FOmfJLSthnq67E6tCJqLWaZldY12KmUuQE3cztARDSvPafmpd4OMOsSnaagSAJvefDEJTAgjqAb2uhi0RY41UEpL5uN7x9GrASxi8mYCyGNxja0UvsVMkEkyNHBSzDo1EhLMJZJZxeU0iit0vItzDDSyiKGwnMjGlPaVN8GMIsKBi4pesDDfEWn3inhHGaiwSkzsTGtpYqGnoTz0WO9EWEyzn0TxagODEn3FGYAuZY5z9VMFGXMzH/K1QnTE9Jo/dJzZ803U8z6WnEI9qCMHa3xXJHsrq8NbLae9FJLBDYdV9jehzCVwpZzZD4pGVZdmJ3gIqOkM6mp1NO9KtErgpoYE4Ivfrd7VBqgbx/x8zVmUJpJ1XkOtvqrsAO5K7Ep0qIEIiR8FptSFIruS8IWC4QNy3qzTkVGhAN1urdZ5pGRMIEEW2J3FCmgN56oDBDPV1W2Puj2MqiBAgxJbXdExrGKHk6Ss+kOOlDot0sh1qYCkRdLEL3auNhmhESby5LvN4KwyB0I9zW4DJLB3H1BTMqdbrzelAu+aUy6bMpfSVl7tK8JO+3Q6UOhu4DFhIm4Qc4agi5xFqBtAZzJPLceIqVbB+4qI5vbf9FY1N+8/wDkm3qmeehNcf1VhdaDME0VlceCjZKIDKlzS/laaTCp5txx0rEbG+824iSeaaSUAJS93MbwfdPCqMkWsIiIskKXiJQJnSjKmCXlL6YrdqzRa2PDWgTJHN4ilswJ5lmNfimZN5tgJjWoYWTbcrBBOQF7c2Y3LllLt2dWG983KMEZLsg6JxvQLFg2HQ3NqQ2EESc20PYvuUAYQEkYWwllMbE7UCbnx8H9oD+5e9R2mo8s8B9tSY6xbG9PczuN6FmB0AfMfdSmr+3qBp2UhrQ5y0ssv+U9/wAUG0dK2HyXpzSXaM0ZKQlvDvIjntxeHdHAPBNvw09gPE40Gsok60iApiVZ7XD7oNYruR9MIakHakQlk4C+Vju0ZIbsMvfB5UE4XQWZ3dVq7p6ssebFOSVJbBPYIe7BQRat4Ietn2pzchKJGFNnoFQDBWSAAGYYcNopiEt2WALq7watXIm2ji33O+lRt88wq9Njs1ZS62ZPgLHmgFXsSB0NOstWzOb3zVu/7mloS9J/57pNmnidakC0PJmdqNJgtMuDpzwCgAmA6XozaOraaIIkk5v8UaZ9/VFMyP1xSL9LTUj00pnv5pI70Bx0tQGrFr/7SrW/NbC9Je0dali5Qzdd4GJpWLNuNW7NIWEE6rHFsDWYsSxJ7Ny880Kq8+opApJKLOZOakW5SO7fsFChcLEGG2kgx1ioEnJCzizMTpOLjmoBtcqAoDTZkwsQmhTAat4tM9YvwtRisQJQugylZSQZCkzm31mZZ0DpelLQDYA+xt2oU2Ecpdrcw4jvTnN3nB2181zWxH7egOahpbz0qf4/5TFyh11ru+6QyVCTIb2j1T09C0npThc4rKv26VL7zSaFO1DbJRxk8VbgBMB2sWO+55oQiuJVhI6C1RZlEX7MMlIG6Wso2WiWxeKXAzbKpyxAdKTK2ZdszpBcPmmi7ZlyGrYE9U2oJ3YRtr2T2qdJ1owhnO7rNWyosOmtkxPW9DJFZVLwSsOb0hpdeTKerI7BWrJe15XqABSRRBcKLlLRO1Fa4VpN0SAl22daVkIOurvp0rOR4liekxTswNkF+yr4owh8DD3Ye0d6tgst7/JE+GKKlFtNlvUh3oDa/a3umbPkgOsE+yoCpvaOuIJx2oy6AaP+RUQlIEGAGxg+akQS7W7avgqIvJMe6sRr802tqgc/2jNn/KAUNEFcks4v/I91va3o0TrKziiIA81LYI/dKaZnmvnElKGDpSnNKCykXjV46Ug6hN25LEd6hULIC2sy6tIZpZDkmsjpmVZhIozdQ5xawd7CrsLAxA20uk9zS+p6pWocjSyIVrwWQSgGAgJvSCgzyXpzYqax94rOPf8AIKWcxcrVK/31/wCKmNfih7Hcx8fdSZVc4g+ZoHry61C4az00ShSLsTyUMIZQSJnOM8WoHJ++aNwRhbu1AoeV+SR6NqBeA++1DiJfHzepdG3mkj/D/wBVNoCSUZNWwFamZZvR3BsYtI1ZGHC3B6HQ80zkQWV66YCelDsGDhwZnSMfmmVOUxAAF0JDp5zFCi7AZ7n4oBgBkHlbDrKNNLdd3Nxg6FQAF0I3xr3qxmjIlkAEGLZOWmISInRdvi9NEEkDeBaQAHyrBAOI7Er8FKhDmBF0hU9og0uzPI1d0odY7s9KVsiQnMHBy0QGbcvMQxP1egi1hN2PilCwDawd/wC0YyhGk/T+0zPVhnreosmVbEzbR2vSOYzeiNKR4i1v01ligM1iUT2v/lZKN271DSOtGGGXWlejahZaeTrbtFKEwxiYjn/xvUVKLCfjikEW1nNERY6kg2hc5BB1G9KurLKt1+6AkYuHZkV0tDTy1Ny9JslBaZtlmTxpQABeSTQgCbmkMVFlAgMsxqWg2KkTD6P7TGoNC8dsFXYt7/NGRYBpMv55o1p4Z/nahUQO8V3HGaUItPuKvFnt90AACphnfSto6AfBnmnUs9X+f2iDA62v8ovUm6icF3aUOM0elMMM2m5OhbapyOcSunfQqVsvwo7+a+Gik3P/AJFiMMgWSzhdQI70lAmVRQ6lozgk0qA9oXT6uvM96xEzsXOAICC15edKRBraGQ0yAX1aCGICWWd5sCFptcOKJEznuLdBZag2tUgIsYQOCZHaXo6lxknHV1moYqLCQA3mVBEuWY0pCkGYX2vr3ak5WwuA5hIY0LVNRiXcgbrMcxK9aPMAwtQuzwXLQ9r0lELEwX8VcQMgtGdbbZp2Zde+alZZgT/lRIErtp33qxxCUmZZXbxvpTUAcObdO1FU0epva2AurfjDQrPzp31pIB8QGqzHjNQEi7AMM34tirSUtVi/QCx1VouV1nHi778YoxY+qUDEc6NOZ9VAzM6f7WpwaUH/AG/mk27x7phApUvITOpzG/oom+Ea9LU/55qSd/Xfepf9wUWR1JwDN5AAh4Iop2/aVszSwJ4q5z880tOrdbc1veN6dpHe9MRZHe1npbzNAl0SQp1N6UZRrC2qxv8A8o4AxG2d++9HCABxN50mKSxZP4vN6QSkTq28T9UziotG1A3SJpgXu5tjpUDZz7pTrbhKYktO+vWpz+ioOE0ydqBjHr/vSg3leWmwG3n6rrVD/wCBTqoZQMIMAgTragiO1ljuxepkKsQsxO8mO8VJqLmaTbVHIFFJFqUulEqxBoEu0U1ksIqAE3bt880pDVWUGiFuJq60MlpALjK2bxehvIhNykNG0z2tSwFQoXbwwmYmIbE4mo64izBViAm7DldKRJiUkxOYgycULQjCUDiFjvNJvwAAggUgYZsskwcUtcwXz10vTwtqwAF1IKdjtQbuxySYVN0Gw6l7yNDsjeKReLyxr/pQEXl1384pmYs6WmfruFKKqEiXTdLN7F4LLeoAwIszh5iA0MzrUGGGsQd8Ba2lVlihGoaruv3UKRRDdmfqjX12SliZdiQ8UrZyh90Gr4+1qFCNoSe1imBIIKnM7ZKhLxkNNh70mvWj0tmh5R0CSznWsch4/T7oTlX7p06lTMgmWJxh2CAMB/5weL8bRzUHFucUbkn6/cVB8nNDRUdazSzbztSC7hjfl4oSRY1AXerdzXoK9FIKZpkDEut/OKVbDkCfIMdqLIYcZPkrqfl6oSZXkozC6VG3vF6JEE69KudP1qmEyZB+nSoLkztPxihPTmtLk1lqXSObx2ZpxITeZl8R/wBrYTtUclMKZx+/aUOkdGu1RRkrBLhdH4JoYiV2LR1jXg908EsXT+sXqAQwmSNVsk6zUuGSbanlnPurokiUu6FrZlO3SmREpmMukp4/IxNWTCG2omgExwSKbtxwI50pDJksDMNtGxG1MKpArC4aQWOgKi0Jh1LeKglQAiRJwBqXwqdUIEgBUlhoDOFG0zTQvEkLaZBAyq7pe+KYwAPc7CL6jUjQRCKdMcomzNrVMmdsuSsgQEsA5IZhaNnKGUVJMTYRpACitC4bpBq0KYGDM4kfT2KMZVCDFbIQaX4DBQRU75JfEYe7LtUO6bQARrC/yt8GIFEHQg8FBJNicqVOloMo7hLXOCbdd6E3jeLIHvEx47VCzBsfe9b2AV2YD7qfdMUkpYEWidLRczRxaH9tvXh0/wDPto4N8XtBsDiIq5XXqYdfj/ylMlKda5JY90Mkuj2jFI1of/PenpvUn8rV6neKhZlZtpxfw96knUpAnLobRq1lt1fqgBKvo9XioGwvA3P8qBnlWoI1/tIvUnO+nzareLXp2TAChsWSX7RxJRQZW3K4cAiTZuu1qlYLJtLEATvuBEGZoAEohhKOgoWMYL1eQiOjC9ye6tTFiTCcG1XxljrFyeGpg0vFNVoikX+KTlOMHbNJr2op/9k='); 1080 1081// wikimedia_death_of_socrates.jpg 1082_via_basic_demo_img.push('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/4QDmRXhpZgAATU0AKgAAAAgABwEaAAUAAAABAAAAYgEbAAUAAAABAAAAagEoAAMAAAABAAIAAAE7AAIAAAAOAAAAcgITAAMAAAABAAEAAIKYAAIAAAAzAAAAgIdpAAQAAAABAAAAtAAAAAAAAABIAAAAAQAAAEgAAAABVHJ1amlsbG8gSnVhbgBodHRwczovL2NyZWF0aXZlY29tbW9ucy5vcmcvcHVibGljZG9tYWluL3plcm8vMS4wLwAAAAOQAAAHAAAABDAyMTCgAAAHAAAABDAxMDCgAQADAAAAAf//AAAAAAAA/+EELWh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8APD94cGFja2V0IGJlZ2luPSfvu78nIGlkPSdXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQnPz4KPHg6eG1wbWV0YSB4bWxuczp4PSdhZG9iZTpuczptZXRhLyc+CjxyZGY6UkRGIHhtbG5zOnJkZj0naHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyc+CgogPHJkZjpEZXNjcmlwdGlvbiB4bWxuczpkYz0naHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8nPgogIDxkYzpkZXNjcmlwdGlvbj4KICAgPHJkZjpBbHQ+CiAgICA8cmRmOmxpIHhtbDpsYW5nPSd4LWRlZmF1bHQnPngtZGVmYXVsdDwvcmRmOmxpPgogICA8L3JkZjpBbHQ+CiAgPC9kYzpkZXNjcmlwdGlvbj4KIDwvcmRmOkRlc2NyaXB0aW9uPgoKIDxyZGY6RGVzY3JpcHRpb24geG1sbnM6ZXhpZj0naHR0cDovL25zLmFkb2JlLmNvbS9leGlmLzEuMC8nPgogIDxleGlmOlhSZXNvbHV0aW9uPjcyPC9leGlmOlhSZXNvbHV0aW9uPgogIDxleGlmOllSZXNvbHV0aW9uPjcyPC9leGlmOllSZXNvbHV0aW9uPgogIDxleGlmOlJlc29sdXRpb25Vbml0PkluY2g8L2V4aWY6UmVzb2x1dGlvblVuaXQ+CiAgPGV4aWY6QXJ0aXN0PlRydWppbGxvIEp1YW48L2V4aWY6QXJ0aXN0PgogIDxleGlmOllDYkNyUG9z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'); 1083</script> 1084<!-- END: Contents of file: src/demo/_via_basic_demo.js--> 1085<!-- START: Contents of file: via.js--> 1086<script> 1087/* 1088VGG Image Annotator (via) 1089www.robots.ox.ac.uk/~vgg/software/via/ 1090 1091Copyright (c) 2016-2019, Abhishek Dutta, Visual Geometry Group, Oxford University and VIA Contributors. 1092All rights reserved. 1093 1094Redistribution and use in source and binary forms, with or without 1095modification, are permitted provided that the following conditions are met: 1096 1097Redistributions of source code must retain the above copyright notice, this 1098list of conditions and the following disclaimer. 1099Redistributions in binary form must reproduce the above copyright notice, 1100this list of conditions and the following disclaimer in the documentation 1101and/or other materials provided with the distribution. 1102THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 1103AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1104IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1105ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 1106LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 1107CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 1108SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 1109INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 1110CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 1111ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 1112POSSIBILITY OF SUCH DAMAGE. 1113*/ 1114 1115/* 1116Links: 1117- https://gitlab.com/vgg/via/blob/master/Contributors.md : list of developers who have contributed code to the VIA project. 1118- https://gitlab.com/vgg/via/blob/master/CodeDoc.md : source code documentation 1119- https://gitlab.com/vgg/via/blob/master/CONTRIBUTING.md : guide for contributors 1120 1121This source code can be grouped into the following categories: 1122- Data structure for annotations 1123- Initialization routine 1124- Handlers for top navigation bar 1125- Local file uploaders 1126- Data Importer 1127- Data Exporter 1128- Maintainers of user interface 1129- Image click handlers 1130- Canvas update routines 1131- Region collision routines 1132- Shortcut key handlers 1133- Persistence of annotation data in browser cache (i.e. localStorage) 1134- Handlers for attributes input panel (spreadsheet like user input panel) 1135*/ 1136 1137"use strict"; 1138 1139var VIA_VERSION = '2.0.12'; 1140var VIA_NAME = 'VGG Image Annotator'; 1141var VIA_SHORT_NAME = 'VIA'; 1142var VIA_REGION_SHAPE = { RECT:'rect', 1143CIRCLE:'circle', 1144ELLIPSE:'ellipse', 1145POLYGON:'polygon', 1146POINT:'point', 1147POLYLINE:'polyline' 1148}; 1149 1150var VIA_ATTRIBUTE_TYPE = { TEXT:'text', 1151CHECKBOX:'checkbox', 1152RADIO:'radio', 1153IMAGE:'image', 1154DROPDOWN:'dropdown' 1155}; 1156 1157var VIA_DISPLAY_AREA_CONTENT_NAME = {IMAGE:'image_panel', 1158IMAGE_GRID:'image_grid_panel', 1159SETTINGS:'settings_panel', 1160PAGE_404:'page_404', 1161PAGE_GETTING_STARTED:'page_getting_started', 1162PAGE_ABOUT:'page_about', 1163PAGE_START_INFO:'page_start_info', 1164PAGE_LICENSE:'page_license' 1165}; 1166 1167var VIA_ANNOTATION_EDITOR_MODE = {SINGLE_REGION:'single_region', 1168ALL_REGIONS:'all_regions'}; 1169var VIA_ANNOTATION_EDITOR_PLACEMENT = {NEAR_REGION:'NEAR_REGION', 1170IMAGE_BOTTOM:'IMAGE_BOTTOM', 1171DISABLE:'DISABLE'}; 1172 1173var VIA_REGION_EDGE_TOL = 5; // pixel 1174var VIA_REGION_CONTROL_POINT_SIZE = 2; 1175var VIA_POLYGON_VERTEX_MATCH_TOL = 10; 1176var VIA_REGION_MIN_DIM = 3; 1177var VIA_MOUSE_CLICK_TOL = 2; 1178var VIA_ELLIPSE_EDGE_TOL = 0.2; // euclidean distance 1179var VIA_THETA_TOL = Math.PI/18; // 10 degrees 1180var VIA_POLYGON_RESIZE_VERTEX_OFFSET = 100; 1181var VIA_CANVAS_DEFAULT_ZOOM_LEVEL_INDEX = 3; 1182var VIA_CANVAS_ZOOM_LEVELS = [0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 2.5, 3.0, 4, 5, 6, 7, 8, 9, 10]; 1183var VIA_REGION_COLOR_LIST = ["#E69F00", "#56B4E9", "#009E73", "#D55E00", "#CC79A7", "#F0E442", "#ffffff"]; 1184// radius of control points in all shapes 1185var VIA_REGION_SHAPES_POINTS_RADIUS = 3; 1186// radius of control points in a point 1187var VIA_REGION_POINT_RADIUS = 3; 1188var VIA_REGION_POINT_RADIUS_DEFAULT = 3; 1189 1190var VIA_THEME_REGION_BOUNDARY_WIDTH = 3; 1191var VIA_THEME_BOUNDARY_LINE_COLOR = "black"; 1192var VIA_THEME_BOUNDARY_FILL_COLOR = "yellow"; 1193var VIA_THEME_SEL_REGION_FILL_COLOR = "#808080"; 1194var VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR = "yellow"; 1195var VIA_THEME_SEL_REGION_OPACITY = 0.5; 1196var VIA_THEME_MESSAGE_TIMEOUT_MS = 6000; 1197var VIA_THEME_CONTROL_POINT_COLOR = '#ff0000'; 1198 1199var VIA_CSV_SEP = ','; 1200var VIA_CSV_QUOTE_CHAR = '"'; 1201var VIA_CSV_KEYVAL_SEP = ':'; 1202 1203var _via_img_metadata = {}; // data structure to store loaded images metadata 1204var _via_img_src = {}; // image content {abs. path, url, base64 data, etc} 1205var _via_img_fileref = {}; // reference to local images selected by using browser file selector 1206var _via_img_count = 0; // count of the loaded images 1207var _via_canvas_regions = []; // image regions spec. in canvas space 1208var _via_canvas_scale = 1.0;// current scale of canvas image 1209 1210var _via_image_id = ''; // id={filename+length} of current image 1211var _via_image_index = -1; // index 1212 1213var _via_current_image_filename; 1214var _via_current_image; 1215var _via_current_image_width; 1216var _via_current_image_height; 1217 1218// a record of image statistics (e.g. width, height) 1219var _via_img_stat = {}; 1220var _via_is_all_img_stat_read_ongoing = false; 1221var _via_img_stat_current_img_index = false; 1222 1223// image canvas 1224var _via_display_area = document.getElementById('display_area'); 1225var _via_img_panel = document.getElementById('image_panel'); 1226var _via_reg_canvas = document.getElementById('region_canvas'); 1227var _via_reg_ctx; // initialized in _via_init() 1228var _via_canvas_width, _via_canvas_height; 1229 1230// canvas zoom 1231var _via_canvas_zoom_level_index = VIA_CANVAS_DEFAULT_ZOOM_LEVEL_INDEX; // 1.0 1232var _via_canvas_scale_without_zoom = 1.0; 1233 1234// state of the application 1235var _via_is_user_drawing_region = false; 1236var _via_current_image_loaded = false; 1237var _via_is_window_resized = false; 1238var _via_is_user_resizing_region = false; 1239var _via_is_user_moving_region = false; 1240var _via_is_user_drawing_polygon = false; 1241var _via_is_region_selected = false; 1242var _via_is_all_region_selected = false; 1243var _via_is_loaded_img_list_visible = false; 1244var _via_is_attributes_panel_visible = false; 1245var _via_is_reg_attr_panel_visible = false; 1246var _via_is_file_attr_panel_visible = false; 1247var _via_is_canvas_zoomed = false; 1248var _via_is_loading_current_image = false; 1249var _via_is_region_id_visible = true; 1250var _via_is_region_boundary_visible = true; 1251var _via_is_region_info_visible = false; 1252var _via_is_ctrl_pressed = false; 1253var _via_is_debug_mode = false; 1254var _via_is_message_visible = true; 1255 1256// region 1257var _via_current_shape = VIA_REGION_SHAPE.RECT; 1258var _via_current_polygon_region_id = -1; 1259var _via_user_sel_region_id = -1; 1260var _via_click_x0 = 0; var _via_click_y0 = 0; 1261var _via_click_x1 = 0; var _via_click_y1 = 0; 1262var _via_region_click_x, _via_region_click_y; 1263var _via_region_edge = [-1, -1]; 1264var _via_current_x = 0; var _via_current_y = 0; 1265 1266// region copy/paste 1267var _via_region_selected_flag = []; // region select flag for current image 1268var _via_copied_image_regions = []; 1269var _via_paste_to_multiple_images_input; 1270 1271// message 1272var _via_message_clear_timer; 1273 1274// attributes 1275var _via_attribute_being_updated = 'region'; // {region, file} 1276var _via_attributes = { 'region':{}, 'file':{} }; 1277var _via_current_attribute_id = ''; 1278 1279// region group color 1280var _via_canvas_regions_group_color = {}; // color of each region 1281 1282// invoke a method after receiving user input 1283var _via_user_input_ok_handler = null; 1284var _via_user_input_cancel_handler = null; 1285var _via_user_input_data = {}; 1286 1287// annotation editor 1288var _via_annotaion_editor_panel = document.getElementById('annotation_editor_panel'); 1289var _via_metadata_being_updated = 'region'; // {region, file} 1290var _via_annotation_editor_mode = VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION; 1291 1292// persistence to local storage 1293var _via_is_local_storage_available = false; 1294var _via_is_save_ongoing = false; 1295 1296// all the image_id and image_filename of images added by the user is 1297// stored in _via_image_id_list and _via_image_filename_list 1298// 1299// Image filename list (img_fn_list) contains a filtered list of images 1300// currently accessible by the user. The img_fn_list is visible in the 1301// left side toolbar. image_grid, next/prev, etc operations depend on 1302// the contents of _via_img_fn_list_img_index_list. 1303var _via_image_id_list = []; // array of all image id (in order they were added by user) 1304var _via_image_filename_list = []; // array of all image filename 1305var _via_image_load_error = []; // {true, false} 1306var _via_image_filepath_resolved = []; // {true, false} 1307var _via_image_filepath_id_list = []; // path for each file 1308 1309var _via_reload_img_fn_list_table = true; 1310var _via_img_fn_list_img_index_list = []; // image index list of images show in img_fn_list 1311var _via_img_fn_list_html = []; // html representation of image filename list 1312 1313// image grid 1314var image_grid_panel = document.getElementById('image_grid_panel'); 1315var _via_display_area_content_name = ''; // describes what is currently shown in display area 1316var _via_display_area_content_name_prev = ''; 1317var _via_image_grid_requires_update = false; 1318var _via_image_grid_content_overflow = false; 1319var _via_image_grid_load_ongoing = false; 1320var _via_image_grid_page_first_index = 0; // array index in _via_img_fn_list_img_index_list[] 1321var _via_image_grid_page_last_index = -1; 1322var _via_image_grid_selected_img_index_list = []; 1323var _via_image_grid_page_img_index_list = []; // list of all image index in current page of image grid 1324var _via_image_grid_visible_img_index_list = []; // list of images currently visible in grid 1325var _via_image_grid_mousedown_img_index = -1; 1326var _via_image_grid_mouseup_img_index = -1; 1327var _via_image_grid_img_index_list = []; // list of all image index in the image grid 1328var _via_image_grid_region_index_list = []; // list of all image index in the image grid 1329var _via_image_grid_group = {}; // {'value':[image_index_list]} 1330var _via_image_grid_group_var = []; // {type, name, value} 1331var _via_image_grid_group_show_all = false; 1332var _via_image_grid_stack_prev_page = []; // stack of first img index of every page navigated so far 1333 1334// image buffer 1335var VIA_IMG_PRELOAD_INDICES = [1, -1, 2, 3, -2, 4]; // for any image, preload previous 2 and next 4 images 1336var VIA_IMG_PRELOAD_COUNT = 4; 1337var _via_buffer_preload_img_index = -1; 1338var _via_buffer_img_index_list = []; 1339var _via_buffer_img_shown_timestamp = []; 1340var _via_preload_img_promise_list = []; 1341 1342// via settings 1343var _via_settings = {}; 1344_via_settings.ui = {}; 1345_via_settings.ui.annotation_editor_height = 25; // in percent of the height of browser window 1346_via_settings.ui.annotation_editor_fontsize = 0.8;// in rem 1347_via_settings.ui.leftsidebar_width = 18; // in rem 1348 1349_via_settings.ui.image_grid = {}; 1350_via_settings.ui.image_grid.img_height = 80; // in pixel 1351_via_settings.ui.image_grid.rshape_fill = 'none'; 1352_via_settings.ui.image_grid.rshape_fill_opacity = 0.3; 1353_via_settings.ui.image_grid.rshape_stroke = 'yellow'; 1354_via_settings.ui.image_grid.rshape_stroke_width = 2; 1355_via_settings.ui.image_grid.show_region_shape = true; 1356_via_settings.ui.image_grid.show_image_policy = 'all'; 1357 1358_via_settings.ui.image = {}; 1359_via_settings.ui.image.region_label = '__via_region_id__'; // default: region_id 1360_via_settings.ui.image.region_color = '__via_default_region_color__'; // default color: yellow 1361_via_settings.ui.image.region_label_font = '10px Sans'; 1362_via_settings.ui.image.on_image_annotation_editor_placement = VIA_ANNOTATION_EDITOR_PLACEMENT.NEAR_REGION; 1363 1364_via_settings.core = {}; 1365_via_settings.core.buffer_size = 4*VIA_IMG_PRELOAD_COUNT + 2; 1366_via_settings.core.filepath = {}; 1367_via_settings.core.default_filepath = ''; 1368 1369// UI html elements 1370var invisible_file_input = document.getElementById("invisible_file_input"); 1371var display_area = document.getElementById("display_area"); 1372var ui_top_panel = document.getElementById("ui_top_panel"); 1373var image_panel = document.getElementById("image_panel"); 1374var img_buffer_now = document.getElementById("img_buffer_now"); 1375 1376var annotation_list_snippet = document.getElementById("annotation_list_snippet"); 1377var annotation_textarea = document.getElementById("annotation_textarea"); 1378 1379var img_fn_list_panel = document.getElementById('img_fn_list_panel'); 1380var img_fn_list = document.getElementById('img_fn_list'); 1381var attributes_panel = document.getElementById('attributes_panel'); 1382var leftsidebar = document.getElementById('leftsidebar'); 1383 1384var BBOX_LINE_WIDTH = 4; 1385var BBOX_SELECTED_OPACITY = 0.3; 1386var BBOX_BOUNDARY_FILL_COLOR_ANNOTATED = "#f2f2f2"; 1387var BBOX_BOUNDARY_FILL_COLOR_NEW = "#aaeeff"; 1388var BBOX_BOUNDARY_LINE_COLOR = "#1a1a1a"; 1389var BBOX_SELECTED_FILL_COLOR = "#ffffff"; 1390 1391var VIA_ANNOTATION_EDITOR_HEIGHT_CHANGE = 5; // in percent 1392var VIA_ANNOTATION_EDITOR_FONTSIZE_CHANGE = 0.1; // in rem 1393var VIA_IMAGE_GRID_IMG_HEIGHT_CHANGE = 20; // in percent 1394var VIA_LEFTSIDEBAR_WIDTH_CHANGE = 1; // in rem 1395var VIA_POLYGON_SEGMENT_SUBTENDED_ANGLE = 5; // in degree (used to approximate shapes using polygon) 1396var VIA_FLOAT_PRECISION = 3; // number of decimal places to include in float values 1397 1398// COCO Export 1399var VIA_COCO_EXPORT_RSHAPE = ['rect', 'circle', 'ellipse', 'polygon', 'point']; 1400var VIA_COCO_EXPORT_ATTRIBUTE_TYPE = [VIA_ATTRIBUTE_TYPE.DROPDOWN, 1401VIA_ATTRIBUTE_TYPE.RADIO]; 1402// 1403// Data structure to store metadata about file and regions 1404// 1405function file_metadata(filename, size) { 1406this.filename = filename; 1407this.size = size; // file size in bytes 1408this.regions = []; // array of file_region() 1409this.file_attributes = {}; // image attributes 1410} 1411 1412function file_region() { 1413this.shape_attributes = {}; // region shape attributes 1414this.region_attributes = {}; // region attributes 1415} 1416 1417// 1418// Initialization routine 1419// 1420function _via_init() { 1421console.log(VIA_NAME); 1422show_message(VIA_NAME + ' (' + VIA_SHORT_NAME + ') version ' + VIA_VERSION + 1423'. Ready !', 2*VIA_THEME_MESSAGE_TIMEOUT_MS); 1424 1425if ( _via_is_debug_mode ) { 1426document.getElementById('ui_top_panel').innerHTML += '<span>DEBUG MODE</span>'; 1427} 1428 1429document.getElementById('img_fn_list').style.display = 'block'; 1430document.getElementById('leftsidebar').style.display = 'table-cell'; 1431 1432// initialize default project 1433project_init_default_project(); 1434 1435// initialize region canvas 2D context 1436_via_init_reg_canvas_context(); 1437 1438// initialize user input handlers (for both window and via_reg_canvas) 1439// handles drawing of regions by user over the image 1440_via_init_keyboard_handlers(); 1441_via_init_mouse_handlers(); 1442 1443// initialize image grid 1444image_grid_init(); 1445 1446show_single_image_view(); 1447init_leftsidebar_accordion(); 1448attribute_update_panel_set_active_button(); 1449annotation_editor_set_active_button(); 1450init_message_panel(); 1451 1452// run attached sub-modules (if any) 1453// e.g. demo modules 1454if (typeof _via_load_submodules === 'function') { 1455console.log('Loading VIA submodule'); 1456setTimeout( async function() { 1457await _via_load_submodules(); 1458}, 100); 1459} 1460 1461} 1462 1463function _via_init_reg_canvas_context() { 1464_via_reg_ctx = _via_reg_canvas.getContext('2d'); 1465} 1466 1467function _via_init_keyboard_handlers() { 1468window.addEventListener('keydown', _via_window_keydown_handler, false); 1469_via_reg_canvas.addEventListener('keydown', _via_reg_canvas_keydown_handler, false); 1470_via_reg_canvas.addEventListener('keyup', _via_reg_canvas_keyup_handler, false); 1471} 1472 1473// handles drawing of regions over image by the user 1474function _via_init_mouse_handlers() { 1475_via_reg_canvas.addEventListener('dblclick', _via_reg_canvas_dblclick_handler, false); 1476_via_reg_canvas.addEventListener('mousedown', _via_reg_canvas_mousedown_handler, false); 1477_via_reg_canvas.addEventListener('mouseup', _via_reg_canvas_mouseup_handler, false); 1478_via_reg_canvas.addEventListener('mouseover', _via_reg_canvas_mouseover_handler, false); 1479_via_reg_canvas.addEventListener('mousemove', _via_reg_canvas_mousemove_handler, false); 1480_via_reg_canvas.addEventListener('wheel', _via_reg_canvas_mouse_wheel_listener, false); 1481// touch screen event handlers 1482// @todo: adapt for mobile users 1483_via_reg_canvas.addEventListener('touchstart', _via_reg_canvas_mousedown_handler, false); 1484_via_reg_canvas.addEventListener('touchend', _via_reg_canvas_mouseup_handler, false); 1485_via_reg_canvas.addEventListener('touchmove', _via_reg_canvas_mousemove_handler, false); 1486} 1487 1488// 1489// Download image with annotations 1490// 1491 1492function download_as_image() { 1493if ( _via_display_area_content_name !== VIA_DISPLAY_AREA_CONTENT_NAME['IMAGE'] ) { 1494show_message('This functionality is only available in single image view mode'); 1495return; 1496} else { 1497var c = document.createElement('canvas'); 1498 1499// ensures that downloaded image is scaled at current zoom level 1500c.width = _via_reg_canvas.width; 1501c.height = _via_reg_canvas.height; 1502 1503var ct = c.getContext('2d'); 1504// draw current image 1505ct.drawImage(_via_current_image, 0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 1506// draw current regions 1507ct.drawImage(_via_reg_canvas, 0, 0); 1508 1509var cur_img_mime = 'image/jpeg'; 1510if ( _via_current_image.src.startsWith('data:') ) { 1511var c1 = _via_current_image.src.indexOf(':', 0); 1512var c2 = _via_current_image.src.indexOf(';', c1); 1513cur_img_mime = _via_current_image.src.substring(c1 + 1, c2); 1514} 1515 1516// extract image data from canvas 1517var saved_img = c.toDataURL(cur_img_mime); 1518saved_img.replace(cur_img_mime, "image/octet-stream"); 1519 1520// simulate user click to trigger download of image 1521var a = document.createElement('a'); 1522a.href = saved_img; 1523a.target = '_blank'; 1524a.download = _via_current_image_filename; 1525 1526// simulate a mouse click event 1527var event = new MouseEvent('click', { 1528view: window, 1529bubbles: true, 1530cancelable: true 1531}); 1532 1533a.dispatchEvent(event); 1534} 1535} 1536 1537// 1538// Display area content 1539// 1540function clear_display_area() { 1541var panels = document.getElementsByClassName('display_area_content'); 1542var i; 1543for ( i = 0; i < panels.length; ++i ) { 1544panels[i].classList.add('display_none'); 1545} 1546} 1547 1548function is_content_name_valid(content_name) { 1549var e; 1550for ( e in VIA_DISPLAY_AREA_CONTENT_NAME ) { 1551if ( VIA_DISPLAY_AREA_CONTENT_NAME[e] === content_name ) { 1552return true; 1553} 1554} 1555return false; 1556} 1557 1558function show_home_panel() { 1559show_single_image_view(); 1560} 1561 1562function set_display_area_content(content_name) { 1563if ( is_content_name_valid(content_name) ) { 1564_via_display_area_content_name_prev = _via_display_area_content_name; 1565clear_display_area(); 1566var p = document.getElementById(content_name); 1567p.classList.remove('display_none'); 1568_via_display_area_content_name = content_name; 1569} 1570} 1571 1572function show_single_image_view() { 1573if (_via_current_image_loaded) { 1574img_fn_list_clear_all_style(); 1575_via_show_img(_via_image_index); 1576set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE); 1577annotation_editor_update_content(); 1578 1579var p = document.getElementById('toolbar_image_grid_toggle'); 1580p.firstChild.setAttribute('xlink:href', '#icon_gridon'); 1581p.childNodes[1].innerHTML = 'Switch to Image Grid View'; 1582} else { 1583set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_START_INFO); 1584} 1585} 1586 1587function show_image_grid_view() { 1588if (_via_current_image_loaded) { 1589img_fn_list_clear_all_style(); 1590set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID); 1591image_grid_toolbar_update_group_by_select(); 1592 1593if ( _via_image_grid_group_var.length === 0 ) { 1594image_grid_show_all_project_images(); 1595} 1596annotation_editor_update_content(); 1597 1598var p = document.getElementById('toolbar_image_grid_toggle'); 1599p.firstChild.setAttribute('xlink:href', '#icon_gridoff'); 1600p.childNodes[1].innerHTML = 'Switch to Single Image View'; 1601 1602//edit_file_metadata_in_annotation_editor(); 1603} else { 1604set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_START_INFO); 1605} 1606} 1607 1608// 1609// Handlers for top navigation bar 1610// 1611function sel_local_images() { 1612// source: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications 1613if (invisible_file_input) { 1614invisible_file_input.setAttribute('multiple', 'multiple'); 1615invisible_file_input.accept = '.jpg,.jpeg,.png,.bmp'; 1616invisible_file_input.onchange = project_file_add_local; 1617invisible_file_input.click(); 1618} 1619} 1620 1621// invoked by menu-item buttons in HTML UI 1622function download_all_region_data(type, file_extension) { 1623if ( typeof(file_extension) === 'undefined' ) { 1624file_extension = type; 1625} 1626// Javascript strings (DOMString) is automatically converted to utf-8 1627// see: https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob 1628pack_via_metadata(type).then( function(data) { 1629var blob_attr = {type: 'text/'+file_extension+';charset=utf-8'}; 1630var all_region_data_blob = new Blob(data, blob_attr); 1631 1632var filename = 'via_export'; 1633if(typeof(_via_settings) !== 'undefined' && 1634_via_settings.hasOwnProperty('project') && 1635_via_settings['project']['name'] !== '') { 1636filename = _via_settings['project']['name']; 1637} 1638if ( file_extension !== 'csv' || file_extension !== 'json' ) { 1639filename += '_' + type + '.' + file_extension; 1640} 1641save_data_to_local_file(all_region_data_blob, filename); 1642}.bind(this), function(err) { 1643show_message('Failed to download data: [' + err + ']'); 1644}.bind(this)); 1645} 1646 1647function sel_local_data_file(type) { 1648if (invisible_file_input) { 1649switch(type) { 1650case 'annotations': 1651invisible_file_input.accept='.csv,.json'; 1652invisible_file_input.onchange = import_annotations_from_file; 1653break; 1654 1655case 'annotations_coco': 1656invisible_file_input.accept='.json'; 1657invisible_file_input.onchange = load_coco_annotations_json_file; 1658break; 1659 1660case 'files_url': 1661invisible_file_input.accept=''; 1662invisible_file_input.onchange = import_files_url_from_file; 1663break; 1664 1665case 'attributes': 1666invisible_file_input.accept='json'; 1667invisible_file_input.onchange = project_import_attributes_from_file; 1668break; 1669 1670default: 1671console.log('sel_local_data_file() : unknown type ' + type); 1672return; 1673} 1674invisible_file_input.removeAttribute('multiple'); 1675invisible_file_input.click(); 1676} 1677} 1678 1679// 1680// Data Importer 1681// 1682function import_files_url_from_file(event) { 1683var selected_files = event.target.files; 1684var i, file; 1685for ( i = 0; i < selected_files.length; ++i ) { 1686file = selected_files[i]; 1687load_text_file(file, import_files_url_from_csv); 1688} 1689} 1690 1691function import_annotations_from_file(event) { 1692var selected_files = event.target.files; 1693var i, file; 1694for ( i = 0; i < selected_files.length; ++i ) { 1695file = selected_files[i]; 1696switch ( file.type ) { 1697case '': // Fall-through // Windows 10: Firefox and Chrome do not report filetype 1698show_message('File type for ' + file.name + ' cannot be determined! Assuming text/plain.'); 1699case 'text/plain': // Fall-through 1700case 'application/vnd.ms-excel': // Fall-through // @todo: filetype of VIA csv annotations in Windows 10 , fix this (reported by @Eli Walker) 1701case 'text/csv': 1702load_text_file(file, import_annotations_from_csv); 1703break; 1704 1705case 'text/json': // Fall-through 1706case 'application/json': 1707load_text_file(file, import_annotations_from_json); 1708break; 1709 1710default: 1711show_message('Annotations cannot be imported from file of type ' + file.type); 1712break; 1713} 1714} 1715} 1716 1717function load_coco_annotations_json_file(event) { 1718load_text_file(event.target.files[0], import_coco_annotations_from_json); 1719} 1720 1721function import_annotations_from_csv(data) { 1722return new Promise( function(ok_callback, err_callback) { 1723if ( data === '' || typeof(data) === 'undefined') { 1724err_callback(); 1725} 1726 1727var region_import_count = 0; 1728var malformed_csv_lines_count = 0; 1729var file_added_count = 0; 1730 1731var line_split_regex = new RegExp('\n|\r|\r\n', 'g'); 1732var csvdata = data.split(line_split_regex); 1733 1734var parsed_header = parse_csv_header_line(csvdata[0]); 1735if ( ! parsed_header.is_header ) { 1736show_message('Header line missing in the CSV file'); 1737err_callback(); 1738return; 1739} 1740 1741var n = csvdata.length; 1742var i; 1743var first_img_id = ''; 1744for ( i = 1; i < n; ++i ) { 1745// ignore blank lines 1746if (csvdata[i].charAt(0) === '\n' || csvdata[i].charAt(0) === '') { 1747continue; 1748} 1749 1750var d = parse_csv_line(csvdata[i]); 1751 1752// check if csv line was malformed 1753if ( d.length !== parsed_header.csv_column_count ) { 1754malformed_csv_lines_count += 1; 1755continue; 1756} 1757 1758var filename = d[parsed_header.filename_index]; 1759var size = d[parsed_header.size_index]; 1760var img_id = _via_get_image_id(filename, size); 1761 1762// check if file is already present in this project 1763if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 1764img_id = project_add_new_file(filename, size); 1765if ( _via_settings.core.default_filepath === '' ) { 1766_via_img_src[img_id] = filename; 1767} else { 1768_via_file_resolve_file_to_default_filepath(img_id); 1769} 1770file_added_count += 1; 1771 1772if ( first_img_id === '' ) { 1773first_img_id = img_id; 1774} 1775} 1776 1777// copy file attributes 1778if ( d[parsed_header.file_attr_index] !== '"{}"') { 1779var fattr = d[parsed_header.file_attr_index]; 1780fattr = remove_prefix_suffix_quotes( fattr ); 1781fattr = unescape_from_csv( fattr ); 1782 1783var m = json_str_to_map( fattr ); 1784for( var key in m ) { 1785_via_img_metadata[img_id].file_attributes[key] = m[key]; 1786 1787// add this file attribute to _via_attributes 1788if ( ! _via_attributes['file'].hasOwnProperty(key) ) { 1789_via_attributes['file'][key] = { 'type':'text' }; 1790} 1791} 1792} 1793 1794var region_i = new file_region(); 1795// copy regions shape attributes 1796if ( d[parsed_header.region_shape_attr_index] !== '"{}"' ) { 1797var sattr = d[parsed_header.region_shape_attr_index]; 1798sattr = remove_prefix_suffix_quotes( sattr ); 1799sattr = unescape_from_csv( sattr ); 1800 1801var m = json_str_to_map( sattr ); 1802for ( var key in m ) { 1803region_i.shape_attributes[key] = m[key]; 1804} 1805} 1806 1807// copy region attributes 1808if ( d[parsed_header.region_attr_index] !== '"{}"' ) { 1809var rattr = d[parsed_header.region_attr_index]; 1810rattr = remove_prefix_suffix_quotes( rattr ); 1811rattr = unescape_from_csv( rattr ); 1812 1813var m = json_str_to_map( rattr ); 1814for ( var key in m ) { 1815region_i.region_attributes[key] = m[key]; 1816 1817// add this region attribute to _via_attributes 1818if ( ! _via_attributes['region'].hasOwnProperty(key) ) { 1819_via_attributes['region'][key] = { 'type':'text' }; 1820} 1821} 1822} 1823 1824// add regions only if they are present 1825if (Object.keys(region_i.shape_attributes).length > 0 || 1826Object.keys(region_i.region_attributes).length > 0 ) { 1827_via_img_metadata[img_id].regions.push(region_i); 1828region_import_count += 1; 1829} 1830} 1831show_message('Import Summary : [' + file_added_count + '] new files, ' + 1832'[' + region_import_count + '] regions, ' + 1833'[' + malformed_csv_lines_count + '] malformed csv lines.'); 1834 1835if ( file_added_count ) { 1836update_img_fn_list(); 1837} 1838 1839if ( _via_current_image_loaded ) { 1840if ( region_import_count ) { 1841update_attributes_update_panel(); 1842annotation_editor_update_content(); 1843_via_load_canvas_regions(); // image to canvas space transform 1844_via_redraw_reg_canvas(); 1845_via_reg_canvas.focus(); 1846} 1847} else { 1848if ( file_added_count ) { 1849var first_img_index = _via_image_id_list.indexOf(first_img_id); 1850_via_show_img( first_img_index ); 1851} 1852} 1853ok_callback([file_added_count, region_import_count, malformed_csv_lines_count]); 1854}); 1855} 1856 1857function parse_csv_header_line(line) { 1858var header_via_10x = '#filename,file_size,file_attributes,region_count,region_id,region_shape_attributes,region_attributes'; // VIA versions 1.0.x 1859var header_via_11x = 'filename,file_size,file_attributes,region_count,region_id,region_shape_attributes,region_attributes'; // VIA version 1.1.x 1860 1861if ( line === header_via_10x || line === header_via_11x ) { 1862return { 'is_header':true, 1863'filename_index': 0, 1864'size_index': 1, 1865'file_attr_index': 2, 1866'region_shape_attr_index': 5, 1867'region_attr_index': 6, 1868'csv_column_count': 7 1869} 1870} else { 1871return { 'is_header':false }; 1872} 1873} 1874 1875// see http://cocodataset.org/#format-data 1876function import_coco_annotations_from_json(data_str) { 1877return new Promise( function(ok_callback, err_callback) { 1878if (data_str === '' || typeof(data_str) === 'undefined') { 1879show_message('Empty file'); 1880return; 1881} 1882var coco = JSON.parse(data_str); 1883if( !coco.hasOwnProperty('info') || 1884!coco.hasOwnProperty('categories') || 1885!coco.hasOwnProperty('annotations') || 1886!coco.hasOwnProperty('images') ) { 1887show_message('File does not contain valid annotations in COCO format.'); 1888return; 1889} 1890 1891// create _via_attributes from coco['categories'] 1892var category_id_to_attribute_name = {}; 1893for( var i in coco['categories'] ) { 1894var sc = coco['categories'][i]['supercategory']; 1895var cid = coco['categories'][i]['id']; 1896var cname = coco['categories'][i]['name']; 1897if( !_via_attributes['region'].hasOwnProperty(sc)) { 1898_via_attributes['region'][sc] = {'type':VIA_ATTRIBUTE_TYPE.RADIO, 1899'description':'coco["categories"][' + i + ']=' + JSON.stringify(coco['categories'][i]), 1900'options':{}, 1901'default_options':{} 1902}; 1903} 1904_via_attributes['region'][sc]['options'][cid] = cname; 1905category_id_to_attribute_name[cid] = sc; 1906} 1907// if more than 5 options, convert the attribute type to DROPDOWN 1908for( var attr_name in _via_attributes['region'] ) { 1909if( Object.keys(_via_attributes['region'][attr_name]['options']).length > 5 ) { 1910_via_attributes['region'][attr_name]['type'] = VIA_ATTRIBUTE_TYPE.DROPDOWN; 1911} 1912} 1913 1914// create an map of image_id and their annotations 1915var image_id_to_annotation_index = {}; 1916for ( var annotation_index in coco['annotations'] ) { 1917var coco_image_id = coco.annotations[annotation_index]['image_id']; 1918if ( !image_id_to_annotation_index.hasOwnProperty(coco_image_id) ) { 1919image_id_to_annotation_index[coco_image_id] = []; 1920} 1921image_id_to_annotation_index[coco_image_id].push( annotation_index ); 1922} 1923 1924// add all files and annotations 1925_via_img_metadata = {}; 1926_via_image_id_list = []; 1927_via_image_filename_list = []; 1928_via_img_count = 0; 1929var imported_file_count = 0; 1930var imported_region_count = 0; 1931for ( var coco_img_index in coco['images'] ) { 1932var coco_img_id = coco['images'][coco_img_index]['id']; 1933var filename; 1934if ( coco.images[coco_img_index].hasOwnProperty('coco_url') && 1935coco.images[coco_img_index]['coco_url'] !== "") { 1936filename = coco.images[coco_img_index]['coco_url']; 1937} else { 1938filename = coco.images[coco_img_index]['file_name']; 1939} 1940_via_img_metadata[coco_img_id] = { 'filename':filename, 1941'size' :-1, 1942'regions' :[], 1943'file_attributes': { 1944'width' :coco.images[coco_img_index]['width'], 1945'height':coco.images[coco_img_index]['height'] 1946}, 1947}; 1948_via_image_id_list.push(coco_img_id); 1949_via_image_filename_list.push(filename); 1950_via_img_count = _via_img_count + 1; 1951 1952// add all annotations associated with this file 1953if ( image_id_to_annotation_index.hasOwnProperty(coco_img_id) ) { 1954for ( var i in image_id_to_annotation_index[coco_img_id] ) { 1955var annotation_i = coco['annotations'][ image_id_to_annotation_index[coco_img_id][i] ]; 1956var bbox_from_polygon = polygon_to_bbox(annotation_i['segmentation'][0]); 1957 1958// ensure rectangles get imported as rectangle (and not as polygon) 1959var is_rectangle = true; 1960for (var j = 0; j < annotation_i['bbox'].length; ++j) { 1961if (annotation_i['bbox'][j] !== bbox_from_polygon[j]) { 1962is_rectangle = false; 1963break; 1964} 1965} 1966 1967var region_i = { 'shape_attributes': {}, 'region_attributes': {} }; 1968var attribute_name = category_id_to_attribute_name[ annotation_i['category_id'] ]; 1969var attribute_value = annotation_i['category_id'].toString(); 1970region_i['region_attributes'][attribute_name] = attribute_value; 1971 1972if ( annotation_i['segmentation'][0].length === 8 && is_rectangle ) { 1973region_i['shape_attributes'] = { 'name':'rect', 1974'x': annotation_i['bbox'][0], 1975'y': annotation_i['bbox'][1], 1976'width': annotation_i['bbox'][2], 1977'height': annotation_i['bbox'][3]}; 1978} else { 1979region_i['shape_attributes'] = { 'name':'polygon', 1980'all_points_x':[], 1981'all_points_y':[]}; 1982for ( var j = 0; j < annotation_i['segmentation'][0].length; j = j + 2 ) { 1983region_i['shape_attributes']['all_points_x'].push( annotation_i['segmentation'][0][j] ); 1984region_i['shape_attributes']['all_points_y'].push( annotation_i['segmentation'][0][j+1] ); 1985} 1986} 1987_via_img_metadata[coco_img_id]['regions'].push(region_i); 1988imported_region_count = imported_region_count + 1; 1989} 1990} 1991} 1992show_message('Import Summary : [' + _via_img_count + '] new files, ' + 1993'[' + imported_region_count + '] regions.'); 1994 1995if(_via_img_count) { 1996update_img_fn_list(); 1997} 1998 1999if(_via_current_image_loaded) { 2000if(imported_region_count) { 2001update_attributes_update_panel(); 2002annotation_editor_update_content(); 2003_via_load_canvas_regions(); // image to canvas space transform 2004_via_redraw_reg_canvas(); 2005_via_reg_canvas.focus(); 2006} 2007} else { 2008if(_via_img_count) { 2009_via_show_img(0); 2010} 2011} 2012ok_callback([_via_img_count, imported_region_count, 0]); 2013}); 2014} 2015 2016function import_annotations_from_json(data_str) { 2017return new Promise( function(ok_callback, err_callback) { 2018if (data_str === '' || typeof(data_str) === 'undefined') { 2019return; 2020} 2021 2022var d = JSON.parse(data_str); 2023var region_import_count = 0; 2024var file_added_count = 0; 2025var malformed_entries_count = 0; 2026for (var img_id in d) { 2027if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 2028project_add_new_file(d[img_id].filename, d[img_id].size, img_id); 2029if ( _via_settings.core.default_filepath === '' ) { 2030_via_img_src[img_id] = d[img_id].filename; 2031} else { 2032_via_file_resolve_file_to_default_filepath(img_id); 2033} 2034file_added_count += 1; 2035} 2036 2037// copy file attributes 2038for ( var key in d[img_id].file_attributes ) { 2039if ( key === '' ) { 2040continue; 2041} 2042 2043_via_img_metadata[img_id].file_attributes[key] = d[img_id].file_attributes[key]; 2044 2045// add this file attribute to _via_attributes 2046if ( ! _via_attributes['file'].hasOwnProperty(key) ) { 2047_via_attributes['file'][key] = { 'type':'text' }; 2048} 2049} 2050 2051// copy regions 2052var regions = d[img_id].regions; 2053for ( var i in regions ) { 2054var region_i = new file_region(); 2055for ( var sid in regions[i].shape_attributes ) { 2056region_i.shape_attributes[sid] = regions[i].shape_attributes[sid]; 2057} 2058for ( var rid in regions[i].region_attributes ) { 2059if ( rid === '' ) { 2060continue; 2061} 2062 2063region_i.region_attributes[rid] = regions[i].region_attributes[rid]; 2064 2065// add this region attribute to _via_attributes 2066if ( ! _via_attributes['region'].hasOwnProperty(rid) ) { 2067_via_attributes['region'][rid] = { 'type':'text' }; 2068} 2069} 2070 2071// add regions only if they are present 2072if ( Object.keys(region_i.shape_attributes).length > 0 || 2073Object.keys(region_i.region_attributes).length > 0 ) { 2074_via_img_metadata[img_id].regions.push(region_i); 2075region_import_count += 1; 2076} 2077} 2078} 2079show_message('Import Summary : [' + file_added_count + '] new files, ' + 2080'[' + region_import_count + '] regions, ' + 2081'[' + malformed_entries_count + '] malformed entries.'); 2082 2083if ( file_added_count ) { 2084update_img_fn_list(); 2085} 2086 2087if ( _via_current_image_loaded ) { 2088if ( region_import_count ) { 2089update_attributes_update_panel(); 2090annotation_editor_update_content(); 2091_via_load_canvas_regions(); // image to canvas space transform 2092_via_redraw_reg_canvas(); 2093_via_reg_canvas.focus(); 2094} 2095} else { 2096if ( file_added_count ) { 2097_via_show_img(0); 2098} 2099} 2100 2101ok_callback([file_added_count, region_import_count, malformed_entries_count]); 2102}); 2103} 2104 2105// assumes that csv line follows the RFC 4180 standard 2106// see: https://en.wikipedia.org/wiki/Comma-separated_values 2107function parse_csv_line(s, field_separator) { 2108if (typeof(s) === 'undefined' || s.length === 0 ) { 2109return []; 2110} 2111 2112if (typeof(field_separator) === 'undefined') { 2113field_separator = ','; 2114} 2115var double_quote_seen = false; 2116var start = 0; 2117var d = []; 2118 2119var i = 0; 2120while ( i < s.length) { 2121if (s.charAt(i) === field_separator) { 2122if (double_quote_seen) { 2123// field separator inside double quote is ignored 2124i = i + 1; 2125} else { 2126//var part = s.substr(start, i - start); 2127d.push( s.substr(start, i - start) ); 2128start = i + 1; 2129i = i + 1; 2130} 2131} else { 2132if (s.charAt(i) === '"') { 2133if (double_quote_seen) { 2134if (s.charAt(i+1) === '"') { 2135// ignore escaped double quotes 2136i = i + 2; 2137} else { 2138// closing of double quote 2139double_quote_seen = false; 2140i = i + 1; 2141} 2142} else { 2143double_quote_seen = true; 2144start = i; 2145i = i + 1; 2146} 2147} else { 2148i = i + 1; 2149} 2150} 2151 2152} 2153// extract the last field (csv rows have no trailing comma) 2154d.push( s.substr(start) ); 2155return d; 2156} 2157 2158// s = '{"name":"rect","x":188,"y":90,"width":243,"height":233}' 2159function json_str_to_map(s) { 2160if (typeof(s) === 'undefined' || s.length === 0 ) { 2161return {}; 2162} 2163 2164return JSON.parse(s); 2165} 2166 2167// ensure the exported json string conforms to RFC 4180 2168// see: https://en.wikipedia.org/wiki/Comma-separated_values 2169function map_to_json(m) { 2170var s = []; 2171for ( var key in m ) { 2172var v = m[key]; 2173var si = JSON.stringify(key); 2174si += VIA_CSV_KEYVAL_SEP; 2175si += JSON.stringify(v); 2176s.push( si ); 2177} 2178return '{' + s.join(VIA_CSV_SEP) + '}'; 2179} 2180 2181function escape_for_csv(s) { 2182return s.replace(/["]/g, '""'); 2183} 2184 2185function unescape_from_csv(s) { 2186return s.replace(/""/g, '"'); 2187} 2188 2189function remove_prefix_suffix_quotes(s) { 2190if ( s.charAt(0) === '"' && s.charAt(s.length-1) === '"' ) { 2191return s.substr(1, s.length-2); 2192} else { 2193return s; 2194} 2195} 2196 2197function clone_image_region(r0) { 2198var r1 = new file_region(); 2199 2200// copy shape attributes 2201for ( var key in r0.shape_attributes ) { 2202r1.shape_attributes[key] = clone_value(r0.shape_attributes[key]); 2203} 2204 2205// copy region attributes 2206for ( var key in r0.region_attributes ) { 2207r1.region_attributes[key] = clone_value(r0.region_attributes[key]); 2208} 2209return r1; 2210} 2211 2212function clone_value(value) { 2213if ( typeof(value) === 'object' ) { 2214if ( Array.isArray(value) ) { 2215return value.slice(0); 2216} else { 2217var copy = {}; 2218for ( var p in value ) { 2219if ( value.hasOwnProperty(p) ) { 2220copy[p] = clone_value(value[p]); 2221} 2222} 2223return copy; 2224} 2225} 2226return value; 2227} 2228 2229function _via_get_image_id(filename, size) { 2230if ( typeof(size) === 'undefined' ) { 2231return filename; 2232} else { 2233return filename + size; 2234} 2235} 2236 2237function load_text_file(text_file, callback_function) { 2238if (text_file) { 2239var text_reader = new FileReader(); 2240text_reader.addEventListener( 'progress', function(e) { 2241show_message('Loading data from file : ' + text_file.name + ' ... '); 2242}, false); 2243 2244text_reader.addEventListener( 'error', function() { 2245show_message('Error loading data text file : ' + text_file.name + ' !'); 2246callback_function(''); 2247}, false); 2248 2249text_reader.addEventListener( 'load', function() { 2250callback_function(text_reader.result); 2251}, false); 2252text_reader.readAsText(text_file, 'utf-8'); 2253} 2254} 2255 2256function import_files_url_from_csv(data) { 2257return new Promise( function(ok_callback, err_callback) { 2258if ( data === '' || typeof(data) === 'undefined') { 2259err_callback(); 2260} 2261 2262var malformed_url_count = 0; 2263var url_added_count = 0; 2264 2265var line_split_regex = new RegExp('\n|\r|\r\n', 'g'); 2266var csvdata = data.split(line_split_regex); 2267 2268var percent_completed = 0; 2269var n = csvdata.length; 2270var i; 2271var img_id; 2272var first_img_id = ''; 2273for ( i=0; i < n; ++i ) { 2274// ignore blank lines 2275if (csvdata[i].charAt(0) === '\n' || csvdata[i].charAt(0) === '') { 2276malformed_url_count += 1; 2277continue; 2278} else { 2279img_id = project_file_add_url(csvdata[i]); 2280if ( first_img_id === '' ) { 2281first_img_id = img_id; 2282} 2283url_added_count += 1; 2284} 2285} 2286show_message('Added ' + url_added_count + ' files to project'); 2287if ( url_added_count ) { 2288var first_img_index = _via_image_id_list.indexOf(first_img_id); 2289_via_show_img(first_img_index); 2290update_img_fn_list(); 2291} 2292}); 2293} 2294 2295// 2296// Data Exporter 2297// 2298function pack_via_metadata(return_type) { 2299return new Promise( function(ok_callback, err_callback) { 2300if( return_type === 'csv' ) { 2301var csvdata = []; 2302var csvheader = 'filename,file_size,file_attributes,region_count,region_id,region_shape_attributes,region_attributes'; 2303csvdata.push(csvheader); 2304 2305for ( var image_id in _via_img_metadata ) { 2306var fattr = map_to_json( _via_img_metadata[image_id].file_attributes ); 2307fattr = escape_for_csv( fattr ); 2308 2309var prefix = '\n' + _via_img_metadata[image_id].filename; 2310prefix += ',' + _via_img_metadata[image_id].size; 2311prefix += ',"' + fattr + '"'; 2312 2313var r = _via_img_metadata[image_id].regions; 2314 2315if ( r.length !==0 ) { 2316for ( var i = 0; i < r.length; ++i ) { 2317var csvline = []; 2318csvline.push(prefix); 2319csvline.push(r.length); 2320csvline.push(i); 2321 2322var sattr = map_to_json( r[i].shape_attributes ); 2323sattr = '"' + escape_for_csv( sattr ) + '"'; 2324csvline.push(sattr); 2325 2326var rattr = map_to_json( r[i].region_attributes ); 2327rattr = '"' + escape_for_csv( rattr ) + '"'; 2328csvline.push(rattr); 2329csvdata.push( csvline.join(VIA_CSV_SEP) ); 2330} 2331} else { 2332// @todo: reconsider this practice of adding an empty entry 2333csvdata.push(prefix + ',0,0,"{}","{}"'); 2334} 2335} 2336ok_callback(csvdata); 2337} 2338 2339// see http://cocodataset.org/#format-data 2340if( return_type === 'coco' ) { 2341img_stat_set_all().then( function(ok) { 2342var coco = export_project_to_coco_format(); 2343ok_callback( [ coco ] ); 2344}.bind(this), function(err) { 2345err_callback(err); 2346}.bind(this)); 2347} else { 2348// default format is JSON 2349ok_callback( [ JSON.stringify(_via_img_metadata) ] ); 2350} 2351}.bind(this)); 2352} 2353 2354function export_project_to_coco_format() { 2355var coco = { 'info':{}, 'images':[], 'annotations':[], 'licenses':[], 'categories':[] }; 2356coco['info'] = { 'year': new Date().getFullYear(), 2357'version': '1.0', 2358'description': 'VIA project exported to COCO format using VGG Image Annotator (http://www.robots.ox.ac.uk/~vgg/software/via/)', 2359'contributor': '', 2360'url': 'http://www.robots.ox.ac.uk/~vgg/software/via/', 2361'date_created': new Date().toString(), 2362}; 2363coco['licenses'] = [ {'id':0, 'name':'Unknown License', 'url':''} ]; // indicates that license is unknown 2364 2365var skipped_annotation_count = 0; 2366// We want to ensure that a COCO project imported in VIA and then exported again back to 2367// COCO format using VIA retains the image_id and category_id present in the original COCO project. 2368// A VIA project that has been created by importing annotations from a COCO project contains 2369// unique image_id of type integer and contains all unique option id. If we detect this, we reuse 2370// the existing image_id and category_id, otherwise we assign a new unique id sequentially. 2371// Currently, it is not possible to preserve the annotation_id 2372var assign_unique_id = false; 2373for(var img_id in _via_img_metadata) { 2374if(Number.isNaN(parseInt(img_id))) { 2375assign_unique_id = true; // since COCO only supports image_id of type integer, we cannot reuse the VIA's image-id 2376break; 2377} 2378} 2379if(assign_unique_id) { 2380// check if all the options have unique id 2381var attribute_option_id_list = []; 2382for(var attr_name in _via_attributes) { 2383if( !VIA_COCO_EXPORT_ATTRIBUTE_TYPE.includes(_via_attributes[attr_name]['type']) ) { 2384continue; // skip this attribute as it will not be included in COCO export 2385} 2386 2387for(var attr_option_id in _via_attributes[attr_name]['options']) { 2388if(attribute_option_id_list.includes(attr_option_id) || 2389Number.isNaN(parseInt(attr_option_id)) ) { 2390assign_unique_id = true; 2391break; 2392} else { 2393attribute_option_id_list.push(assign_unique_id); 2394} 2395} 2396} 2397} 2398 2399// add categories 2400var attr_option_id_to_category_id = {}; 2401var unique_category_id = 1; 2402for(var attr_name in _via_attributes['region']) { 2403if( VIA_COCO_EXPORT_ATTRIBUTE_TYPE.includes(_via_attributes['region'][attr_name]['type']) ) { 2404for(var attr_option_id in _via_attributes['region'][attr_name]['options']) { 2405var category_id; 2406if(assign_unique_id) { 2407category_id = unique_category_id; 2408unique_category_id = unique_category_id + 1; 2409} else { 2410category_id = parseInt(attr_option_id); 2411} 2412coco['categories'].push({ 2413'supercategory':attr_name, 2414'id':category_id, 2415'name':_via_attributes['region'][attr_name]['options'][attr_option_id] 2416}); 2417attr_option_id_to_category_id[attr_option_id] = category_id; 2418} 2419} 2420} 2421 2422// add files and all their associated annotations 2423var annotation_id = 1; 2424var unique_img_id = 1; 2425for( var img_index in _via_image_id_list ) { 2426var img_id = _via_image_id_list[img_index]; 2427var file_src = _via_settings['core']['default_filepath'] + _via_img_metadata[img_id].filename; 2428if ( _via_img_fileref[img_id] instanceof File ) { 2429file_src = _via_img_fileref[img_id].filename; 2430} 2431 2432var coco_img_id; 2433if(assign_unique_id) { 2434coco_img_id = unique_img_id; 2435unique_img_id = unique_img_id + 1; 2436} else { 2437coco_img_id = parseInt(img_id); 2438} 2439 2440coco['images'].push( { 2441'id':coco_img_id, 2442'width':_via_img_stat[img_index][0], 2443'height':_via_img_stat[img_index][1], 2444'file_name':_via_img_metadata[img_id].filename, 2445'license':0, 2446'flickr_url':file_src, 2447'coco_url':file_src, 2448'date_captured':'', 2449} ); 2450 2451// add all annotations associated with this file 2452for( var rindex in _via_img_metadata[img_id].regions ) { 2453var region = _via_img_metadata[img_id].regions[rindex]; 2454if( !VIA_COCO_EXPORT_RSHAPE.includes(region.shape_attributes['name']) ) { 2455skipped_annotation_count = skipped_annotation_count + 1; 2456continue; // skip this region as COCO does not allow it 2457} 2458 2459var coco_annotation = via_region_shape_to_coco_annotation(region.shape_attributes); 2460coco_annotation['id'] = annotation_id; 2461coco_annotation['image_id'] = coco_img_id; 2462 2463var region_aid_list = Object.keys(region['region_attributes']); 2464for(var region_attribute_id in region['region_attributes']) { 2465var region_attribute_value = region['region_attributes'][region_attribute_id]; 2466if(attr_option_id_to_category_id.hasOwnProperty(region_attribute_value)) { 2467coco_annotation['category_id'] = attr_option_id_to_category_id[region_attribute_value]; 2468coco['annotations'].push(coco_annotation); 2469annotation_id = annotation_id + 1; 2470} else { 2471skipped_annotation_count = skipped_annotation_count + 1; 2472continue; // skip attribute value not supported by COCO format 2473} 2474} 2475} 2476} 2477 2478show_message('Skipped ' + skipped_annotation_count + ' annotations. COCO format only supports the following attribute types: ' + JSON.stringify(VIA_COCO_EXPORT_ATTRIBUTE_TYPE) + ' and region shapes: ' + JSON.stringify(VIA_COCO_EXPORT_RSHAPE)); 2479return [ JSON.stringify(coco) ]; 2480} 2481 2482function via_region_shape_to_coco_annotation(shape_attributes) { 2483var annotation = { 'segmentation':[[]], 'area':[], 'bbox':[], 'iscrowd':0 }; 2484 2485switch(shape_attributes['name']) { 2486case 'rect': 2487var x0 = shape_attributes['x']; 2488var y0 = shape_attributes['y']; 2489var w = parseInt(shape_attributes['width']); 2490var h = parseInt(shape_attributes['height']); 2491var x1 = x0 + w; 2492var y1 = y0 + h; 2493annotation['segmentation'][0] = [x0, y0, x1, y0, x1, y1, x0, y1]; 2494annotation['area'] = w * h ; 2495 2496annotation['bbox'] = [x0, y0, w, h]; 2497break; 2498 2499case 'point': 2500var cx = shape_attributes['cx']; 2501var cy = shape_attributes['cy']; 2502// 2 is for visibility - currently set to always inside segmentation. 2503// see Keypoint Detection: http://cocodataset.org/#format-data 2504annotation['keypoints'] = [cx, cy, 2]; 2505annotation['num_keypoints'] = 1; 2506break; 2507 2508case 'circle': 2509var a,b; 2510a = shape_attributes['r']; 2511b = shape_attributes['r']; 2512var theta_to_radian = Math.PI/180; 2513 2514for ( var theta = 0; theta < 360; theta = theta + VIA_POLYGON_SEGMENT_SUBTENDED_ANGLE ) { 2515var theta_radian = theta * theta_to_radian; 2516var x = shape_attributes['cx'] + a * Math.cos(theta_radian); 2517var y = shape_attributes['cy'] + b * Math.sin(theta_radian); 2518annotation['segmentation'][0].push( fixfloat(x), fixfloat(y) ); 2519} 2520annotation['bbox'] = polygon_to_bbox(annotation['segmentation'][0]); 2521annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]; 2522break; 2523 2524case 'ellipse': 2525var a,b; 2526a = shape_attributes['rx']; 2527b = shape_attributes['ry']; 2528var rotation = 0; 2529// older version of VIA2 did not support rotated ellipse and hence 'theta' attribute may not be available 2530if( shape_attributes.hasOwnProperty('theta') ) { 2531rotation = shape_attributes['theta']; 2532} 2533 2534var theta_to_radian = Math.PI/180; 2535 2536for ( var theta = 0; theta < 360; theta = theta + VIA_POLYGON_SEGMENT_SUBTENDED_ANGLE ) { 2537var theta_radian = theta * theta_to_radian; 2538var x = shape_attributes['cx'] + 2539( a * Math.cos(theta_radian) * Math.cos(rotation) ) - 2540( b * Math.sin(theta_radian) * Math.sin(rotation) ); 2541var y = shape_attributes['cy'] + 2542( a * Math.cos(theta_radian) * Math.sin(rotation) ) + 2543( b * Math.sin(theta_radian) * Math.cos(rotation) ); 2544annotation['segmentation'][0].push( fixfloat(x), fixfloat(y) ); 2545} 2546annotation['bbox'] = polygon_to_bbox(annotation['segmentation'][0]); 2547annotation['area'] = annotation['bbox'][2] * annotation['bbox'][3]; 2548break; 2549 2550case 'polygon': 2551annotation['segmentation'][0] = []; 2552var x0 = +Infinity; 2553var y0 = +Infinity; 2554var x1 = -Infinity; 2555var y1 = -Infinity; 2556for ( var i in shape_attributes['all_points_x'] ) { 2557annotation['segmentation'][0].push( shape_attributes['all_points_x'][i] ); 2558annotation['segmentation'][0].push( shape_attributes['all_points_y'][i] ); 2559if ( shape_attributes['all_points_x'][i] < x0 ) { 2560x0 = shape_attributes['all_points_x'][i]; 2561} 2562if ( shape_attributes['all_points_y'][i] < y0 ) { 2563y0 = shape_attributes['all_points_y'][i]; 2564} 2565if ( shape_attributes['all_points_x'][i] > x1 ) { 2566x1 = shape_attributes['all_points_x'][i]; 2567} 2568if ( shape_attributes['all_points_y'][i] > y1 ) { 2569y1 = shape_attributes['all_points_y'][i]; 2570} 2571} 2572var w = x1 - x0; 2573var h = y1 - y0; 2574annotation['bbox'] = [x0, y0, w, h]; 2575annotation['area'] = w * h; // approximate area 2576} 2577return annotation; 2578} 2579 2580function save_data_to_local_file(data, filename) { 2581var a = document.createElement('a'); 2582a.href = URL.createObjectURL(data); 2583a.download = filename; 2584 2585// simulate a mouse click event 2586var event = new MouseEvent('click', { 2587view: window, 2588bubbles: true, 2589cancelable: true 2590}); 2591a.dispatchEvent(event); 2592 2593// @todo: replace a.dispatchEvent() with a.click() 2594// a.click() based trigger is supported in Chrome 70 and Safari 11/12 but **not** in Firefox 63 2595//a.click(); 2596} 2597 2598// 2599// Maintainers of user interface 2600// 2601 2602function init_message_panel() { 2603var p = document.getElementById('message_panel'); 2604p.addEventListener('mousedown', function() { 2605this.style.display = 'none'; 2606}, false); 2607p.addEventListener('mouseover', function() { 2608clearTimeout(_via_message_clear_timer); // stop any previous timeouts 2609}, false); 2610} 2611 2612function toggle_message_visibility() { 2613if(_via_is_message_visible) { 2614show_message('Disabled status messages'); 2615_via_is_message_visible = false; 2616} else { 2617_via_is_message_visible = true; 2618show_message('Status messages are now visible'); 2619} 2620} 2621 2622function show_message(msg, t) { 2623if ( _via_message_clear_timer ) { 2624clearTimeout(_via_message_clear_timer); // stop any previous timeouts 2625} 2626if ( !_via_is_message_visible ) { 2627return; 2628} 2629 2630var timeout = t; 2631if ( typeof t === 'undefined' ) { 2632timeout = VIA_THEME_MESSAGE_TIMEOUT_MS; 2633} 2634document.getElementById('message_panel_content').innerHTML = msg; 2635document.getElementById('message_panel').style.display = 'block'; 2636 2637_via_message_clear_timer = setTimeout( function() { 2638document.getElementById('message_panel').style.display = 'none'; 2639}, timeout); 2640} 2641 2642function _via_regions_group_color_init() { 2643_via_canvas_regions_group_color = {}; 2644var aid = _via_settings.ui.image.region_color; 2645if ( aid !== '__via_default_region_color__' ) { 2646var avalue; 2647for ( var i = 0; i < _via_img_metadata[_via_image_id].regions.length; ++i ) { 2648avalue = _via_img_metadata[_via_image_id].regions[i].region_attributes[aid]; 2649_via_canvas_regions_group_color[avalue] = 1; 2650} 2651var color_index = 0; 2652for ( avalue in _via_canvas_regions_group_color ) { 2653_via_canvas_regions_group_color[avalue] = VIA_REGION_COLOR_LIST[ color_index % VIA_REGION_COLOR_LIST.length ]; 2654color_index = color_index + 1; 2655} 2656} 2657} 2658 2659// transform regions in image space to canvas space 2660function _via_load_canvas_regions() { 2661_via_regions_group_color_init(); 2662 2663// load all existing annotations into _via_canvas_regions 2664var regions = _via_img_metadata[_via_image_id].regions; 2665_via_canvas_regions = []; 2666for ( var i = 0; i < regions.length; ++i ) { 2667var region_i = new file_region(); 2668for ( var key in regions[i].shape_attributes ) { 2669region_i.shape_attributes[key] = regions[i].shape_attributes[key]; 2670} 2671_via_canvas_regions.push(region_i); 2672 2673switch(_via_canvas_regions[i].shape_attributes['name']) { 2674case VIA_REGION_SHAPE.RECT: 2675var x = regions[i].shape_attributes['x'] / _via_canvas_scale; 2676var y = regions[i].shape_attributes['y'] / _via_canvas_scale; 2677var width = regions[i].shape_attributes['width'] / _via_canvas_scale; 2678var height = regions[i].shape_attributes['height'] / _via_canvas_scale; 2679 2680_via_canvas_regions[i].shape_attributes['x'] = Math.round(x); 2681_via_canvas_regions[i].shape_attributes['y'] = Math.round(y); 2682_via_canvas_regions[i].shape_attributes['width'] = Math.round(width); 2683_via_canvas_regions[i].shape_attributes['height'] = Math.round(height); 2684break; 2685 2686case VIA_REGION_SHAPE.CIRCLE: 2687var cx = regions[i].shape_attributes['cx'] / _via_canvas_scale; 2688var cy = regions[i].shape_attributes['cy'] / _via_canvas_scale; 2689var r = regions[i].shape_attributes['r'] / _via_canvas_scale; 2690_via_canvas_regions[i].shape_attributes['cx'] = Math.round(cx); 2691_via_canvas_regions[i].shape_attributes['cy'] = Math.round(cy); 2692_via_canvas_regions[i].shape_attributes['r'] = Math.round(r); 2693break; 2694 2695case VIA_REGION_SHAPE.ELLIPSE: 2696var cx = regions[i].shape_attributes['cx'] / _via_canvas_scale; 2697var cy = regions[i].shape_attributes['cy'] / _via_canvas_scale; 2698var rx = regions[i].shape_attributes['rx'] / _via_canvas_scale; 2699var ry = regions[i].shape_attributes['ry'] / _via_canvas_scale; 2700// rotation in radians 2701var theta = regions[i].shape_attributes['theta']; 2702_via_canvas_regions[i].shape_attributes['cx'] = Math.round(cx); 2703_via_canvas_regions[i].shape_attributes['cy'] = Math.round(cy); 2704_via_canvas_regions[i].shape_attributes['rx'] = Math.round(rx); 2705_via_canvas_regions[i].shape_attributes['ry'] = Math.round(ry); 2706_via_canvas_regions[i].shape_attributes['theta'] = theta; 2707break; 2708 2709case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 2710case VIA_REGION_SHAPE.POLYGON: 2711var all_points_x = regions[i].shape_attributes['all_points_x'].slice(0); 2712var all_points_y = regions[i].shape_attributes['all_points_y'].slice(0); 2713for (var j=0; j<all_points_x.length; ++j) { 2714all_points_x[j] = Math.round(all_points_x[j] / _via_canvas_scale); 2715all_points_y[j] = Math.round(all_points_y[j] / _via_canvas_scale); 2716} 2717_via_canvas_regions[i].shape_attributes['all_points_x'] = all_points_x; 2718_via_canvas_regions[i].shape_attributes['all_points_y'] = all_points_y; 2719break; 2720 2721case VIA_REGION_SHAPE.POINT: 2722var cx = regions[i].shape_attributes['cx'] / _via_canvas_scale; 2723var cy = regions[i].shape_attributes['cy'] / _via_canvas_scale; 2724 2725_via_canvas_regions[i].shape_attributes['cx'] = Math.round(cx); 2726_via_canvas_regions[i].shape_attributes['cy'] = Math.round(cy); 2727break; 2728} 2729} 2730} 2731 2732// updates currently selected region shape 2733function select_region_shape(sel_shape_name) { 2734for ( var shape_name in VIA_REGION_SHAPE ) { 2735var ui_element = document.getElementById('region_shape_' + VIA_REGION_SHAPE[shape_name]); 2736ui_element.classList.remove('selected'); 2737} 2738 2739_via_current_shape = sel_shape_name; 2740var ui_element = document.getElementById('region_shape_' + _via_current_shape); 2741ui_element.classList.add('selected'); 2742 2743switch(_via_current_shape) { 2744case VIA_REGION_SHAPE.RECT: // Fall-through 2745case VIA_REGION_SHAPE.CIRCLE: // Fall-through 2746case VIA_REGION_SHAPE.ELLIPSE: 2747show_message('Press single click and drag mouse to draw ' + 2748_via_current_shape + ' region'); 2749break; 2750 2751case VIA_REGION_SHAPE.POLYLINE: 2752case VIA_REGION_SHAPE.POLYGON: 2753_via_is_user_drawing_polygon = false; 2754_via_current_polygon_region_id = -1; 2755 2756show_message('[Single Click] to define polygon/polyline vertices, ' + 2757'[Backspace] to delete last vertex, [Enter] to finish, [Esc] to cancel drawing.' ); 2758break; 2759 2760case VIA_REGION_SHAPE.POINT: 2761show_message('Press single click to define points (or landmarks)'); 2762break; 2763 2764default: 2765show_message('Unknown shape selected!'); 2766break; 2767} 2768} 2769 2770function set_all_canvas_size(w, h) { 2771_via_reg_canvas.height = h; 2772_via_reg_canvas.width = w; 2773 2774image_panel.style.height = h + 'px'; 2775image_panel.style.width = w + 'px'; 2776} 2777 2778function set_all_canvas_scale(s) { 2779_via_reg_ctx.scale(s, s); 2780} 2781 2782function show_all_canvas() { 2783image_panel.style.display = 'inline-block'; 2784} 2785 2786function hide_all_canvas() { 2787image_panel.style.display = 'none'; 2788} 2789 2790function jump_to_image(image_index) { 2791if ( _via_img_count <= 0 ) { 2792return; 2793} 2794 2795switch(_via_display_area_content_name) { 2796case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID: 2797if ( image_index >= 0 && image_index < _via_img_count) { 2798// @todo: jump to image grid page view with the given first image index 2799show_single_image_view(); 2800_via_show_img(image_index); 2801} 2802break; 2803default: 2804if ( image_index >= 0 && image_index < _via_img_count) { 2805_via_show_img(image_index); 2806} 2807break; 2808} 2809} 2810 2811function count_missing_region_attr(img_id) { 2812var miss_region_attr_count = 0; 2813var attr_count = Object.keys(_via_region_attributes).length; 2814for( var i=0; i < _via_img_metadata[img_id].regions.length; ++i ) { 2815var set_attr_count = Object.keys(_via_img_metadata[img_id].regions[i].region_attributes).length; 2816miss_region_attr_count += ( attr_count - set_attr_count ); 2817} 2818return miss_region_attr_count; 2819} 2820 2821function count_missing_file_attr(img_id) { 2822return Object.keys(_via_file_attributes).length - Object.keys(_via_img_metadata[img_id].file_attributes).length; 2823} 2824 2825function toggle_all_regions_selection(is_selected) { 2826var n = _via_img_metadata[_via_image_id].regions.length; 2827var i; 2828_via_region_selected_flag = []; 2829for ( i = 0; i < n; ++i) { 2830_via_region_selected_flag[i] = is_selected; 2831} 2832_via_is_all_region_selected = is_selected; 2833annotation_editor_hide(); 2834if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.ALL_REGIONS ) { 2835annotation_editor_clear_row_highlight(); 2836} 2837} 2838 2839function select_only_region(region_id) { 2840toggle_all_regions_selection(false); 2841set_region_select_state(region_id, true); 2842_via_is_region_selected = true; 2843_via_is_all_region_selected = false; 2844_via_user_sel_region_id = region_id; 2845} 2846 2847function set_region_select_state(region_id, is_selected) { 2848_via_region_selected_flag[region_id] = is_selected; 2849} 2850 2851function show_annotation_data() { 2852pack_via_metadata('csv').then( function(data) { 2853var hstr = '<pre>' + data.join('') + '</pre>'; 2854var window_features = 'toolbar=no,menubar=no,location=no,resizable=yes,scrollbars=yes,status=no'; 2855window_features += ',width=800,height=600'; 2856var annotation_data_window = window.open('', 'Annotations (preview) ', window_features); 2857annotation_data_window.document.body.innerHTML = hstr; 2858}.bind(this), function(err) { 2859show_message('Failed to collect annotation data!'); 2860}.bind(this)); 2861} 2862 2863// 2864// Image click handlers 2865// 2866 2867// enter annotation mode on double click 2868function _via_reg_canvas_dblclick_handler(e) { 2869e.stopPropagation(); 2870// @todo: use double click in future 2871} 2872 2873// user clicks on the canvas 2874function _via_reg_canvas_mousedown_handler(e) { 2875e.stopPropagation(); 2876_via_click_x0 = e.offsetX; _via_click_y0 = e.offsetY; 2877_via_region_edge = is_on_region_corner(_via_click_x0, _via_click_y0); 2878var region_id = is_inside_region(_via_click_x0, _via_click_y0); 2879 2880if ( _via_is_region_selected ) { 2881// check if user clicked on the region boundary 2882if ( _via_region_edge[1] > 0 ) { 2883if ( !_via_is_user_resizing_region ) { 2884if ( _via_region_edge[0] !== _via_user_sel_region_id ) { 2885_via_user_sel_region_id = _via_region_edge[0]; 2886} 2887// resize region 2888_via_is_user_resizing_region = true; 2889} 2890} else { 2891var yes = is_inside_this_region(_via_click_x0, 2892_via_click_y0, 2893_via_user_sel_region_id); 2894if (yes) { 2895if( !_via_is_user_moving_region ) { 2896_via_is_user_moving_region = true; 2897_via_region_click_x = _via_click_x0; 2898_via_region_click_y = _via_click_y0; 2899} 2900} 2901if ( region_id === -1 ) { 2902// mousedown on outside any region 2903_via_is_user_drawing_region = true; 2904// unselect all regions 2905_via_is_region_selected = false; 2906_via_user_sel_region_id = -1; 2907toggle_all_regions_selection(false); 2908} 2909} 2910} else { 2911if ( region_id === -1 ) { 2912// mousedown outside a region 2913if (_via_current_shape !== VIA_REGION_SHAPE.POLYGON && 2914_via_current_shape !== VIA_REGION_SHAPE.POLYLINE && 2915_via_current_shape !== VIA_REGION_SHAPE.POINT) { 2916// this is a bounding box drawing event 2917_via_is_user_drawing_region = true; 2918} 2919} else { 2920// mousedown inside a region 2921// this could lead to (1) region selection or (2) region drawing 2922_via_is_user_drawing_region = true; 2923} 2924} 2925} 2926 2927// implements the following functionalities: 2928// - new region drawing (including polygon) 2929// - moving/resizing/select/unselect existing region 2930function _via_reg_canvas_mouseup_handler(e) { 2931e.stopPropagation(); 2932_via_click_x1 = e.offsetX; _via_click_y1 = e.offsetY; 2933 2934var click_dx = Math.abs(_via_click_x1 - _via_click_x0); 2935var click_dy = Math.abs(_via_click_y1 - _via_click_y0); 2936 2937// indicates that user has finished moving a region 2938if ( _via_is_user_moving_region ) { 2939_via_is_user_moving_region = false; 2940_via_reg_canvas.style.cursor = "default"; 2941 2942var move_x = Math.round(_via_click_x1 - _via_region_click_x); 2943var move_y = Math.round(_via_click_y1 - _via_region_click_y); 2944 2945if (Math.abs(move_x) > VIA_MOUSE_CLICK_TOL || 2946Math.abs(move_y) > VIA_MOUSE_CLICK_TOL) { 2947// move all selected regions 2948_via_move_selected_regions(move_x, move_y); 2949} else { 2950// indicates a user click on an already selected region 2951// this could indicate the user's intention to select another 2952// nested region within this region 2953// OR 2954// draw a nested region (i.e. region inside a region) 2955 2956// traverse the canvas regions in alternating ascending 2957// and descending order to solve the issue of nested regions 2958var nested_region_id = is_inside_region(_via_click_x0, _via_click_y0, true); 2959if (nested_region_id >= 0 && 2960nested_region_id !== _via_user_sel_region_id) { 2961_via_user_sel_region_id = nested_region_id; 2962_via_is_region_selected = true; 2963_via_is_user_moving_region = false; 2964 2965// de-select all other regions if the user has not pressed Shift 2966if ( !e.shiftKey ) { 2967toggle_all_regions_selection(false); 2968} 2969set_region_select_state(nested_region_id, true); 2970annotation_editor_show(); 2971} else { 2972// user clicking inside an already selected region 2973// indicates that the user intends to draw a nested region 2974toggle_all_regions_selection(false); 2975_via_is_region_selected = false; 2976 2977switch (_via_current_shape) { 2978case VIA_REGION_SHAPE.POLYLINE: // handled by case for POLYGON 2979case VIA_REGION_SHAPE.POLYGON: 2980// user has clicked on the first point in a new polygon 2981// see also event 'mouseup' for _via_is_user_drawing_polygon=true 2982_via_is_user_drawing_polygon = true; 2983 2984var canvas_polygon_region = new file_region(); 2985canvas_polygon_region.shape_attributes['name'] = _via_current_shape; 2986canvas_polygon_region.shape_attributes['all_points_x'] = [Math.round(_via_click_x0)]; 2987canvas_polygon_region.shape_attributes['all_points_y'] = [Math.round(_via_click_y0)]; 2988var new_length = _via_canvas_regions.push(canvas_polygon_region); 2989_via_current_polygon_region_id = new_length - 1; 2990break; 2991 2992case VIA_REGION_SHAPE.POINT: 2993// user has marked a landmark point 2994var point_region = new file_region(); 2995point_region.shape_attributes['name'] = VIA_REGION_SHAPE.POINT; 2996point_region.shape_attributes['cx'] = Math.round(_via_click_x0 * _via_canvas_scale); 2997point_region.shape_attributes['cy'] = Math.round(_via_click_y0 * _via_canvas_scale); 2998_via_img_metadata[_via_image_id].regions.push(point_region); 2999 3000var canvas_point_region = new file_region(); 3001canvas_point_region.shape_attributes['name'] = VIA_REGION_SHAPE.POINT; 3002canvas_point_region.shape_attributes['cx'] = Math.round(_via_click_x0); 3003canvas_point_region.shape_attributes['cy'] = Math.round(_via_click_y0); 3004_via_canvas_regions.push(canvas_point_region); 3005break; 3006} 3007annotation_editor_update_content(); 3008} 3009} 3010_via_redraw_reg_canvas(); 3011_via_reg_canvas.focus(); 3012return; 3013} 3014 3015// indicates that user has finished resizing a region 3016if ( _via_is_user_resizing_region ) { 3017// _via_click(x0,y0) to _via_click(x1,y1) 3018_via_is_user_resizing_region = false; 3019_via_reg_canvas.style.cursor = "default"; 3020 3021// update the region 3022var region_id = _via_region_edge[0]; 3023var image_attr = _via_img_metadata[_via_image_id].regions[region_id].shape_attributes; 3024var canvas_attr = _via_canvas_regions[region_id].shape_attributes; 3025 3026switch (canvas_attr['name']) { 3027case VIA_REGION_SHAPE.RECT: 3028var d = [canvas_attr['x'], canvas_attr['y'], 0, 0]; 3029d[2] = d[0] + canvas_attr['width']; 3030d[3] = d[1] + canvas_attr['height']; 3031 3032var mx = _via_current_x; 3033var my = _via_current_y; 3034var preserve_aspect_ratio = false; 3035 3036// constrain (mx,my) to lie on a line connecting a diagonal of rectangle 3037if ( _via_is_ctrl_pressed ) { 3038preserve_aspect_ratio = true; 3039} 3040 3041rect_update_corner(_via_region_edge[1], d, mx, my, preserve_aspect_ratio); 3042rect_standardize_coordinates(d); 3043 3044var w = Math.abs(d[2] - d[0]); 3045var h = Math.abs(d[3] - d[1]); 3046 3047image_attr['x'] = Math.round(d[0] * _via_canvas_scale); 3048image_attr['y'] = Math.round(d[1] * _via_canvas_scale); 3049image_attr['width'] = Math.round(w * _via_canvas_scale); 3050image_attr['height'] = Math.round(h * _via_canvas_scale); 3051 3052canvas_attr['x'] = Math.round( image_attr['x'] / _via_canvas_scale); 3053canvas_attr['y'] = Math.round( image_attr['y'] / _via_canvas_scale); 3054canvas_attr['width'] = Math.round( image_attr['width'] / _via_canvas_scale); 3055canvas_attr['height'] = Math.round( image_attr['height'] / _via_canvas_scale); 3056break; 3057 3058case VIA_REGION_SHAPE.CIRCLE: 3059var dx = Math.abs(canvas_attr['cx'] - _via_current_x); 3060var dy = Math.abs(canvas_attr['cy'] - _via_current_y); 3061var new_r = Math.sqrt( dx*dx + dy*dy ); 3062 3063image_attr['r'] = fixfloat(new_r * _via_canvas_scale); 3064canvas_attr['r'] = Math.round( image_attr['r'] / _via_canvas_scale); 3065break; 3066 3067case VIA_REGION_SHAPE.ELLIPSE: 3068var new_rx = canvas_attr['rx']; 3069var new_ry = canvas_attr['ry']; 3070var new_theta = canvas_attr['theta']; 3071var dx = Math.abs(canvas_attr['cx'] - _via_current_x); 3072var dy = Math.abs(canvas_attr['cy'] - _via_current_y); 3073 3074switch(_via_region_edge[1]) { 3075case 5: 3076new_ry = Math.sqrt(dx*dx + dy*dy); 3077new_theta = Math.atan2(- (_via_current_x - canvas_attr['cx']), (_via_current_y - canvas_attr['cy'])); 3078break; 3079 3080case 6: 3081new_rx = Math.sqrt(dx*dx + dy*dy); 3082new_theta = Math.atan2((_via_current_y - canvas_attr['cy']), (_via_current_x - canvas_attr['cx'])); 3083break; 3084 3085default: 3086new_rx = dx; 3087new_ry = dy; 3088new_theta = 0; 3089break; 3090} 3091 3092image_attr['rx'] = fixfloat(new_rx * _via_canvas_scale); 3093image_attr['ry'] = fixfloat(new_ry * _via_canvas_scale); 3094image_attr['theta'] = fixfloat(new_theta); 3095 3096canvas_attr['rx'] = Math.round(image_attr['rx'] / _via_canvas_scale); 3097canvas_attr['ry'] = Math.round(image_attr['ry'] / _via_canvas_scale); 3098canvas_attr['theta'] = fixfloat(new_theta); 3099break; 3100 3101case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3102case VIA_REGION_SHAPE.POLYGON: 3103var moved_vertex_id = _via_region_edge[1] - VIA_POLYGON_RESIZE_VERTEX_OFFSET; 3104 3105if ( e.ctrlKey || e.metaKey ) { 3106// if on vertex, delete it 3107// if on edge, add a new vertex 3108var r = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3109var shape = r.name; 3110var is_on_vertex = is_on_polygon_vertex(r['all_points_x'], r['all_points_y'], _via_current_x, _via_current_y); 3111 3112if ( is_on_vertex === _via_region_edge[1] ) { 3113// click on vertex, hence delete vertex 3114if ( _via_polygon_del_vertex(region_id, moved_vertex_id) ) { 3115show_message('Deleted vertex ' + moved_vertex_id + ' from region'); 3116} 3117} else { 3118var is_on_edge = is_on_polygon_edge(r['all_points_x'], r['all_points_y'], _via_current_x, _via_current_y); 3119if ( is_on_edge === _via_region_edge[1] ) { 3120// click on edge, hence add new vertex 3121var vertex_index = is_on_edge - VIA_POLYGON_RESIZE_VERTEX_OFFSET; 3122var canvas_x0 = Math.round(_via_click_x1); 3123var canvas_y0 = Math.round(_via_click_y1); 3124var img_x0 = Math.round( canvas_x0 * _via_canvas_scale ); 3125var img_y0 = Math.round( canvas_y0 * _via_canvas_scale ); 3126canvas_x0 = Math.round( img_x0 / _via_canvas_scale ); 3127canvas_y0 = Math.round( img_y0 / _via_canvas_scale ); 3128 3129_via_canvas_regions[region_id].shape_attributes['all_points_x'].splice(vertex_index+1, 0, canvas_x0); 3130_via_canvas_regions[region_id].shape_attributes['all_points_y'].splice(vertex_index+1, 0, canvas_y0); 3131_via_img_metadata[_via_image_id].regions[region_id].shape_attributes['all_points_x'].splice(vertex_index+1, 0, img_x0); 3132_via_img_metadata[_via_image_id].regions[region_id].shape_attributes['all_points_y'].splice(vertex_index+1, 0, img_y0); 3133 3134show_message('Added 1 new vertex to ' + shape + ' region'); 3135} 3136} 3137} else { 3138// update coordinate of vertex 3139var imx = Math.round(_via_current_x * _via_canvas_scale); 3140var imy = Math.round(_via_current_y * _via_canvas_scale); 3141image_attr['all_points_x'][moved_vertex_id] = imx; 3142image_attr['all_points_y'][moved_vertex_id] = imy; 3143canvas_attr['all_points_x'][moved_vertex_id] = Math.round( imx / _via_canvas_scale ); 3144canvas_attr['all_points_y'][moved_vertex_id] = Math.round( imy / _via_canvas_scale ); 3145} 3146break; 3147} // end of switch() 3148_via_redraw_reg_canvas(); 3149_via_reg_canvas.focus(); 3150return; 3151} 3152 3153// denotes a single click (= mouse down + mouse up) 3154if ( click_dx < VIA_MOUSE_CLICK_TOL || 3155click_dy < VIA_MOUSE_CLICK_TOL ) { 3156// if user is already drawing polygon, then each click adds a new point 3157if ( _via_is_user_drawing_polygon ) { 3158var canvas_x0 = Math.round(_via_click_x1); 3159var canvas_y0 = Math.round(_via_click_y1); 3160var n = _via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_x'].length; 3161var last_x0 = _via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_x'][n-1]; 3162var last_y0 = _via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_y'][n-1]; 3163// discard if the click was on the last vertex 3164if ( canvas_x0 !== last_x0 || canvas_y0 !== last_y0 ) { 3165// user clicked on a new polygon point 3166_via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_x'].push(canvas_x0); 3167_via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_y'].push(canvas_y0); 3168} 3169} else { 3170var region_id = is_inside_region(_via_click_x0, _via_click_y0); 3171if ( region_id >= 0 ) { 3172// first click selects region 3173_via_user_sel_region_id = region_id; 3174_via_is_region_selected = true; 3175_via_is_user_moving_region = false; 3176_via_is_user_drawing_region = false; 3177 3178// de-select all other regions if the user has not pressed Shift 3179if ( !e.shiftKey ) { 3180annotation_editor_clear_row_highlight(); 3181toggle_all_regions_selection(false); 3182} 3183set_region_select_state(region_id, true); 3184 3185// show annotation editor only when a single region is selected 3186if ( !e.shiftKey ) { 3187annotation_editor_show(); 3188} else { 3189annotation_editor_hide(); 3190} 3191 3192// show the region info 3193if (_via_is_region_info_visible) { 3194var canvas_attr = _via_canvas_regions[region_id].shape_attributes; 3195 3196switch (canvas_attr['name']) { 3197case VIA_REGION_SHAPE.RECT: 3198break; 3199 3200case VIA_REGION_SHAPE.CIRCLE: 3201var rf = document.getElementById('region_info'); 3202var attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3203rf.innerHTML += ',' + ' Radius:' + attr['r']; 3204break; 3205 3206case VIA_REGION_SHAPE.ELLIPSE: 3207var rf = document.getElementById('region_info'); 3208var attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3209rf.innerHTML += ',' + ' X-radius:' + attr['rx'] + ',' + ' Y-radius:' + attr['ry']; 3210break; 3211 3212case VIA_REGION_SHAPE.POLYLINE: 3213case VIA_REGION_SHAPE.POLYGON: 3214break; 3215} 3216} 3217 3218show_message('Region selected. If you intended to draw a region, click again inside the selected region to start drawing a region.') 3219} else { 3220if ( _via_is_user_drawing_region ) { 3221// clear all region selection 3222_via_is_user_drawing_region = false; 3223_via_is_region_selected = false; 3224toggle_all_regions_selection(false); 3225annotation_editor_hide(); 3226} else { 3227switch (_via_current_shape) { 3228case VIA_REGION_SHAPE.POLYLINE: // handled by case for POLYGON 3229case VIA_REGION_SHAPE.POLYGON: 3230// user has clicked on the first point in a new polygon 3231// see also event 'mouseup' for _via_is_user_moving_region=true 3232_via_is_user_drawing_polygon = true; 3233 3234var canvas_polygon_region = new file_region(); 3235canvas_polygon_region.shape_attributes['name'] = _via_current_shape; 3236canvas_polygon_region.shape_attributes['all_points_x'] = [ Math.round(_via_click_x0) ]; 3237canvas_polygon_region.shape_attributes['all_points_y'] = [ Math.round(_via_click_y0)] ; 3238 3239var new_length = _via_canvas_regions.push(canvas_polygon_region); 3240_via_current_polygon_region_id = new_length - 1; 3241break; 3242 3243case VIA_REGION_SHAPE.POINT: 3244// user has marked a landmark point 3245var point_region = new file_region(); 3246point_region.shape_attributes['name'] = VIA_REGION_SHAPE.POINT; 3247point_region.shape_attributes['cx'] = Math.round(_via_click_x0 * _via_canvas_scale); 3248point_region.shape_attributes['cy'] = Math.round(_via_click_y0 * _via_canvas_scale); 3249var region_count = _via_img_metadata[_via_image_id].regions.push(point_region); 3250var new_region_id = region_count - 1; 3251set_region_annotations_to_default_value( new_region_id ); 3252 3253var canvas_point_region = new file_region(); 3254canvas_point_region.shape_attributes['name'] = VIA_REGION_SHAPE.POINT; 3255canvas_point_region.shape_attributes['cx'] = Math.round(_via_click_x0); 3256canvas_point_region.shape_attributes['cy'] = Math.round(_via_click_y0); 3257_via_canvas_regions.push(canvas_point_region); 3258 3259annotation_editor_update_content(); 3260break; 3261} 3262} 3263} 3264} 3265_via_redraw_reg_canvas(); 3266_via_reg_canvas.focus(); 3267return; 3268} 3269 3270// indicates that user has finished drawing a new region 3271if ( _via_is_user_drawing_region ) { 3272_via_is_user_drawing_region = false; 3273var region_x0 = _via_click_x0; 3274var region_y0 = _via_click_y0; 3275var region_x1 = _via_click_x1; 3276var region_y1 = _via_click_y1; 3277 3278var original_img_region = new file_region(); 3279var canvas_img_region = new file_region(); 3280var region_dx = Math.abs(region_x1 - region_x0); 3281var region_dy = Math.abs(region_y1 - region_y0); 3282var new_region_added = false; 3283 3284if ( region_dx > VIA_REGION_MIN_DIM && region_dy > VIA_REGION_MIN_DIM ) { // avoid regions with 0 dim 3285switch(_via_current_shape) { 3286case VIA_REGION_SHAPE.RECT: 3287// ensure that (x0,y0) is top-left and (x1,y1) is bottom-right 3288if ( _via_click_x0 < _via_click_x1 ) { 3289region_x0 = _via_click_x0; 3290region_x1 = _via_click_x1; 3291} else { 3292region_x0 = _via_click_x1; 3293region_x1 = _via_click_x0; 3294} 3295 3296if ( _via_click_y0 < _via_click_y1 ) { 3297region_y0 = _via_click_y0; 3298region_y1 = _via_click_y1; 3299} else { 3300region_y0 = _via_click_y1; 3301region_y1 = _via_click_y0; 3302} 3303 3304var x = Math.round(region_x0 * _via_canvas_scale); 3305var y = Math.round(region_y0 * _via_canvas_scale); 3306var width = Math.round(region_dx * _via_canvas_scale); 3307var height = Math.round(region_dy * _via_canvas_scale); 3308original_img_region.shape_attributes['name'] = 'rect'; 3309original_img_region.shape_attributes['x'] = x; 3310original_img_region.shape_attributes['y'] = y; 3311original_img_region.shape_attributes['width'] = width; 3312original_img_region.shape_attributes['height'] = height; 3313 3314canvas_img_region.shape_attributes['name'] = 'rect'; 3315canvas_img_region.shape_attributes['x'] = Math.round( x / _via_canvas_scale ); 3316canvas_img_region.shape_attributes['y'] = Math.round( y / _via_canvas_scale ); 3317canvas_img_region.shape_attributes['width'] = Math.round( width / _via_canvas_scale ); 3318canvas_img_region.shape_attributes['height'] = Math.round( height / _via_canvas_scale ); 3319 3320new_region_added = true; 3321break; 3322 3323case VIA_REGION_SHAPE.CIRCLE: 3324var cx = Math.round(region_x0 * _via_canvas_scale); 3325var cy = Math.round(region_y0 * _via_canvas_scale); 3326var r = Math.round( Math.sqrt(region_dx*region_dx + region_dy*region_dy) * _via_canvas_scale ); 3327 3328original_img_region.shape_attributes['name'] = 'circle'; 3329original_img_region.shape_attributes['cx'] = cx; 3330original_img_region.shape_attributes['cy'] = cy; 3331original_img_region.shape_attributes['r'] = r; 3332 3333canvas_img_region.shape_attributes['name'] = 'circle'; 3334canvas_img_region.shape_attributes['cx'] = Math.round( cx / _via_canvas_scale ); 3335canvas_img_region.shape_attributes['cy'] = Math.round( cy / _via_canvas_scale ); 3336canvas_img_region.shape_attributes['r'] = Math.round( r / _via_canvas_scale ); 3337 3338new_region_added = true; 3339break; 3340 3341case VIA_REGION_SHAPE.ELLIPSE: 3342var cx = Math.round(region_x0 * _via_canvas_scale); 3343var cy = Math.round(region_y0 * _via_canvas_scale); 3344var rx = Math.round(region_dx * _via_canvas_scale); 3345var ry = Math.round(region_dy * _via_canvas_scale); 3346var theta = 0; 3347 3348original_img_region.shape_attributes['name'] = 'ellipse'; 3349original_img_region.shape_attributes['cx'] = cx; 3350original_img_region.shape_attributes['cy'] = cy; 3351original_img_region.shape_attributes['rx'] = rx; 3352original_img_region.shape_attributes['ry'] = ry; 3353original_img_region.shape_attributes['theta'] = theta; 3354 3355canvas_img_region.shape_attributes['name'] = 'ellipse'; 3356canvas_img_region.shape_attributes['cx'] = Math.round( cx / _via_canvas_scale ); 3357canvas_img_region.shape_attributes['cy'] = Math.round( cy / _via_canvas_scale ); 3358canvas_img_region.shape_attributes['rx'] = Math.round( rx / _via_canvas_scale ); 3359canvas_img_region.shape_attributes['ry'] = Math.round( ry / _via_canvas_scale ); 3360canvas_img_region.shape_attributes['theta'] = theta; 3361 3362new_region_added = true; 3363break; 3364 3365case VIA_REGION_SHAPE.POINT: // handled by case VIA_REGION_SHAPE.POLYGON 3366case VIA_REGION_SHAPE.POLYLINE: // handled by case VIA_REGION_SHAPE.POLYGON 3367case VIA_REGION_SHAPE.POLYGON: 3368// handled by _via_is_user_drawing_polygon 3369break; 3370} // end of switch 3371 3372if ( new_region_added ) { 3373var n1 = _via_img_metadata[_via_image_id].regions.push(original_img_region); 3374var n2 = _via_canvas_regions.push(canvas_img_region); 3375 3376if ( n1 !== n2 ) { 3377console.log('_via_img_metadata.regions[' + n1 + '] and _via_canvas_regions[' + n2 + '] count mismatch'); 3378} 3379var new_region_id = n1 - 1; 3380 3381set_region_annotations_to_default_value( new_region_id ); 3382select_only_region(new_region_id); 3383if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.ALL_REGIONS && 3384_via_metadata_being_updated === 'region' ) { 3385annotation_editor_add_row( new_region_id ); 3386annotation_editor_scroll_to_row( new_region_id ); 3387annotation_editor_clear_row_highlight(); 3388annotation_editor_highlight_row( new_region_id ); 3389} 3390annotation_editor_show(); 3391} 3392_via_redraw_reg_canvas(); 3393_via_reg_canvas.focus(); 3394} else { 3395show_message('Prevented accidental addition of a very small region.'); 3396} 3397return; 3398} 3399} 3400 3401function _via_reg_canvas_mouseover_handler(e) { 3402// change the mouse cursor icon 3403_via_redraw_reg_canvas(); 3404_via_reg_canvas.focus(); 3405} 3406 3407function _via_reg_canvas_mousemove_handler(e) { 3408if ( !_via_current_image_loaded ) { 3409return; 3410} 3411 3412_via_current_x = e.offsetX; _via_current_y = e.offsetY; 3413 3414// display the cursor coordinates 3415var rf = document.getElementById('region_info'); 3416if ( rf != null && _via_is_region_info_visible ) { 3417var img_x = Math.round( _via_current_x * _via_canvas_scale ); 3418var img_y = Math.round( _via_current_y * _via_canvas_scale ); 3419rf.innerHTML = 'X:' + img_x + ',' + ' Y:' + img_y; 3420} 3421 3422if ( _via_is_region_selected ) { 3423// display the region's info if a region is selected 3424if ( rf != null && _via_is_region_info_visible && _via_user_sel_region_id !== -1) { 3425var canvas_attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3426switch (canvas_attr['name']) { 3427case VIA_REGION_SHAPE.RECT: 3428break; 3429 3430case VIA_REGION_SHAPE.CIRCLE: 3431var rf = document.getElementById('region_info'); 3432var attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3433rf.innerHTML += ',' + ' Radius:' + attr['r']; 3434break; 3435 3436case VIA_REGION_SHAPE.ELLIPSE: 3437var rf = document.getElementById('region_info'); 3438var attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3439rf.innerHTML += ',' + ' X-radius:' + attr['rx'] + ',' + ' Y-radius:' + attr['ry']; 3440break; 3441 3442case VIA_REGION_SHAPE.POLYLINE: 3443case VIA_REGION_SHAPE.POLYGON: 3444break; 3445} 3446} 3447 3448if ( !_via_is_user_resizing_region ) { 3449// check if user moved mouse cursor to region boundary 3450// which indicates an intention to resize the region 3451_via_region_edge = is_on_region_corner(_via_current_x, _via_current_y); 3452 3453if ( _via_region_edge[0] === _via_user_sel_region_id ) { 3454switch(_via_region_edge[1]) { 3455// rect 3456case 1: // Fall-through // top-left corner of rect 3457case 3: // bottom-right corner of rect 3458_via_reg_canvas.style.cursor = "nwse-resize"; 3459break; 3460case 2: // Fall-through // top-right corner of rect 3461case 4: // bottom-left corner of rect 3462_via_reg_canvas.style.cursor = "nesw-resize"; 3463break; 3464 3465case 5: // Fall-through // top-middle point of rect 3466case 7: // bottom-middle point of rect 3467_via_reg_canvas.style.cursor = "ns-resize"; 3468break; 3469case 6: // Fall-through // top-middle point of rect 3470case 8: // bottom-middle point of rect 3471_via_reg_canvas.style.cursor = "ew-resize"; 3472break; 3473 3474// circle and ellipse 3475case 5: 3476_via_reg_canvas.style.cursor = "n-resize"; 3477break; 3478case 6: 3479_via_reg_canvas.style.cursor = "e-resize"; 3480break; 3481 3482default: 3483_via_reg_canvas.style.cursor = "default"; 3484break; 3485} 3486 3487if (_via_region_edge[1] >= VIA_POLYGON_RESIZE_VERTEX_OFFSET) { 3488// indicates mouse over polygon vertex 3489_via_reg_canvas.style.cursor = "crosshair"; 3490show_message('To move vertex, simply drag the vertex. To add vertex, press [Ctrl] key and click on the edge. To delete vertex, press [Ctrl] (or [Command]) key and click on vertex.'); 3491} 3492} else { 3493var yes = is_inside_this_region(_via_current_x, 3494_via_current_y, 3495_via_user_sel_region_id); 3496if (yes) { 3497_via_reg_canvas.style.cursor = "move"; 3498} else { 3499_via_reg_canvas.style.cursor = "default"; 3500} 3501 3502} 3503} else { 3504annotation_editor_hide() // resizing 3505} 3506} 3507 3508if(_via_is_user_drawing_region) { 3509// draw region as the user drags the mouse cursor 3510if (_via_canvas_regions.length) { 3511_via_redraw_reg_canvas(); // clear old intermediate rectangle 3512} else { 3513// first region being drawn, just clear the full region canvas 3514_via_reg_ctx.clearRect(0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 3515} 3516 3517var region_x0 = _via_click_x0; 3518var region_y0 = _via_click_y0; 3519 3520var dx = Math.round(Math.abs(_via_current_x - _via_click_x0)); 3521var dy = Math.round(Math.abs(_via_current_y - _via_click_y0)); 3522_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_FILL_COLOR; 3523 3524switch (_via_current_shape ) { 3525case VIA_REGION_SHAPE.RECT: 3526if ( _via_click_x0 < _via_current_x ) { 3527if ( _via_click_y0 < _via_current_y ) { 3528region_x0 = _via_click_x0; 3529region_y0 = _via_click_y0; 3530} else { 3531region_x0 = _via_click_x0; 3532region_y0 = _via_current_y; 3533} 3534} else { 3535if ( _via_click_y0 < _via_current_y ) { 3536region_x0 = _via_current_x; 3537region_y0 = _via_click_y0; 3538} else { 3539region_x0 = _via_current_x; 3540region_y0 = _via_current_y; 3541} 3542} 3543 3544_via_draw_rect_region(region_x0, region_y0, dx, dy, false); 3545 3546// display the current region info 3547if ( rf != null && _via_is_region_info_visible ) { 3548rf.innerHTML += ',' + ' W:' + dx + ',' + ' H:' + dy; 3549} 3550break; 3551 3552case VIA_REGION_SHAPE.CIRCLE: 3553var circle_radius = Math.round(Math.sqrt( dx*dx + dy*dy )); 3554_via_draw_circle_region(region_x0, region_y0, circle_radius, false); 3555 3556// display the current region info 3557if ( rf != null && _via_is_region_info_visible ) { 3558rf.innerHTML += ',' + ' Radius:' + circle_radius; 3559} 3560break; 3561 3562case VIA_REGION_SHAPE.ELLIPSE: 3563_via_draw_ellipse_region(region_x0, region_y0, dx, dy, 0, false); 3564 3565// display the current region info 3566if ( rf != null && _via_is_region_info_visible ) { 3567rf.innerHTML += ',' + ' X-radius:' + fixfloat(dx) + ',' + ' Y-radius:' + fixfloat(dy); 3568} 3569break; 3570 3571case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3572case VIA_REGION_SHAPE.POLYGON: 3573// this is handled by the if ( _via_is_user_drawing_polygon ) { ... } 3574// see below 3575break; 3576} 3577_via_reg_canvas.focus(); 3578} 3579 3580if ( _via_is_user_resizing_region ) { 3581// user has clicked mouse on bounding box edge and is now moving it 3582// draw region as the user drags the mouse coursor 3583if (_via_canvas_regions.length) { 3584_via_redraw_reg_canvas(); // clear old intermediate rectangle 3585} else { 3586// first region being drawn, just clear the full region canvas 3587_via_reg_ctx.clearRect(0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 3588} 3589 3590var region_id = _via_region_edge[0]; 3591var attr = _via_canvas_regions[region_id].shape_attributes; 3592switch (attr['name']) { 3593case VIA_REGION_SHAPE.RECT: 3594// original rectangle 3595var d = [attr['x'], attr['y'], 0, 0]; 3596d[2] = d[0] + attr['width']; 3597d[3] = d[1] + attr['height']; 3598 3599var mx = _via_current_x; 3600var my = _via_current_y; 3601var preserve_aspect_ratio = false; 3602// constrain (mx,my) to lie on a line connecting a diagonal of rectangle 3603if ( _via_is_ctrl_pressed ) { 3604preserve_aspect_ratio = true; 3605} 3606 3607rect_update_corner(_via_region_edge[1], d, mx, my, preserve_aspect_ratio); 3608rect_standardize_coordinates(d); 3609 3610var w = Math.abs(d[2] - d[0]); 3611var h = Math.abs(d[3] - d[1]); 3612_via_draw_rect_region(d[0], d[1], w, h, true); 3613 3614if ( rf != null && _via_is_region_info_visible ) { 3615rf.innerHTML += ',' + ' W:' + w + ',' + ' H:' + h; 3616} 3617break; 3618 3619case VIA_REGION_SHAPE.CIRCLE: 3620var dx = Math.abs(attr['cx'] - _via_current_x); 3621var dy = Math.abs(attr['cy'] - _via_current_y); 3622var new_r = Math.sqrt( dx*dx + dy*dy ); 3623_via_draw_circle_region(attr['cx'], 3624attr['cy'], 3625new_r, 3626true); 3627if ( rf != null && _via_is_region_info_visible ) { 3628var curr_texts = rf.innerHTML.split(","); 3629rf.innerHTML = ""; 3630rf.innerHTML += curr_texts[0] + ',' + curr_texts[1] + ',' + ' Radius:' + Math.round(new_r); 3631} 3632break; 3633 3634case VIA_REGION_SHAPE.ELLIPSE: 3635var new_rx = attr['rx']; 3636var new_ry = attr['ry']; 3637var new_theta = attr['theta']; 3638var dx = Math.abs(attr['cx'] - _via_current_x); 3639var dy = Math.abs(attr['cy'] - _via_current_y); 3640switch(_via_region_edge[1]) { 3641case 5: 3642new_ry = Math.sqrt(dx*dx + dy*dy); 3643new_theta = Math.atan2(- (_via_current_x - attr['cx']), (_via_current_y - attr['cy'])); 3644break; 3645 3646case 6: 3647new_rx = Math.sqrt(dx*dx + dy*dy); 3648new_theta = Math.atan2((_via_current_y - attr['cy']), (_via_current_x - attr['cx'])); 3649break; 3650 3651default: 3652new_rx = dx; 3653new_ry = dy; 3654new_theta = 0; 3655break; 3656} 3657 3658_via_draw_ellipse_region(attr['cx'], 3659attr['cy'], 3660new_rx, 3661new_ry, 3662new_theta, 3663true); 3664if ( rf != null && _via_is_region_info_visible ) { 3665var curr_texts = rf.innerHTML.split(","); 3666rf.innerHTML = ""; 3667rf.innerHTML = curr_texts[0] + ',' + curr_texts[1] + ',' + ' X-radius:' + fixfloat(new_rx) + ',' + ' Y-radius:' + fixfloat(new_ry); 3668} 3669break; 3670 3671case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3672case VIA_REGION_SHAPE.POLYGON: 3673var moved_all_points_x = attr['all_points_x'].slice(0); 3674var moved_all_points_y = attr['all_points_y'].slice(0); 3675var moved_vertex_id = _via_region_edge[1] - VIA_POLYGON_RESIZE_VERTEX_OFFSET; 3676 3677moved_all_points_x[moved_vertex_id] = _via_current_x; 3678moved_all_points_y[moved_vertex_id] = _via_current_y; 3679 3680_via_draw_polygon_region(moved_all_points_x, 3681moved_all_points_y, 3682true, 3683attr['name']); 3684if ( rf != null && _via_is_region_info_visible ) { 3685rf.innerHTML += ',' + ' Vertices:' + attr['all_points_x'].length; 3686} 3687break; 3688} 3689_via_reg_canvas.focus(); 3690} 3691 3692if ( _via_is_user_moving_region ) { 3693// draw region as the user drags the mouse coursor 3694if (_via_canvas_regions.length) { 3695_via_redraw_reg_canvas(); // clear old intermediate rectangle 3696} else { 3697// first region being drawn, just clear the full region canvas 3698_via_reg_ctx.clearRect(0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 3699} 3700 3701var move_x = (_via_current_x - _via_region_click_x); 3702var move_y = (_via_current_y - _via_region_click_y); 3703var attr = _via_canvas_regions[_via_user_sel_region_id].shape_attributes; 3704 3705switch (attr['name']) { 3706case VIA_REGION_SHAPE.RECT: 3707_via_draw_rect_region(attr['x'] + move_x, 3708attr['y'] + move_y, 3709attr['width'], 3710attr['height'], 3711true); 3712// display the current region info 3713if ( rf != null && _via_is_region_info_visible ) { 3714rf.innerHTML += ',' + ' W:' + attr['width'] + ',' + ' H:' + attr['height']; 3715} 3716break; 3717 3718case VIA_REGION_SHAPE.CIRCLE: 3719_via_draw_circle_region(attr['cx'] + move_x, 3720attr['cy'] + move_y, 3721attr['r'], 3722true); 3723break; 3724 3725case VIA_REGION_SHAPE.ELLIPSE: 3726if (typeof(attr['theta']) === 'undefined') { attr['theta'] = 0; } 3727_via_draw_ellipse_region(attr['cx'] + move_x, 3728attr['cy'] + move_y, 3729attr['rx'], 3730attr['ry'], 3731attr['theta'], 3732true); 3733break; 3734 3735case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3736case VIA_REGION_SHAPE.POLYGON: 3737var moved_all_points_x = attr['all_points_x'].slice(0); 3738var moved_all_points_y = attr['all_points_y'].slice(0); 3739for (var i=0; i<moved_all_points_x.length; ++i) { 3740moved_all_points_x[i] += move_x; 3741moved_all_points_y[i] += move_y; 3742} 3743_via_draw_polygon_region(moved_all_points_x, 3744moved_all_points_y, 3745true, 3746attr['name']); 3747if ( rf != null && _via_is_region_info_visible ) { 3748rf.innerHTML += ',' + ' Vertices:' + attr['all_points_x'].length; 3749} 3750break; 3751 3752case VIA_REGION_SHAPE.POINT: 3753_via_draw_point_region(attr['cx'] + move_x, 3754attr['cy'] + move_y, 3755true); 3756break; 3757} 3758_via_reg_canvas.focus(); 3759annotation_editor_hide() // moving 3760return; 3761} 3762 3763if ( _via_is_user_drawing_polygon ) { 3764_via_redraw_reg_canvas(); 3765var attr = _via_canvas_regions[_via_current_polygon_region_id].shape_attributes; 3766var all_points_x = attr['all_points_x']; 3767var all_points_y = attr['all_points_y']; 3768var npts = all_points_x.length; 3769 3770if ( npts > 0 ) { 3771var line_x = [all_points_x.slice(npts-1), _via_current_x]; 3772var line_y = [all_points_y.slice(npts-1), _via_current_y]; 3773_via_draw_polygon_region(line_x, line_y, false, attr['name']); 3774} 3775 3776if ( rf != null && _via_is_region_info_visible ) { 3777rf.innerHTML += ',' + ' Vertices:' + npts; 3778} 3779} 3780} 3781 3782function _via_move_selected_regions(move_x, move_y) { 3783var i, n; 3784n = _via_region_selected_flag.length; 3785for ( i = 0; i < n; ++i ) { 3786if ( _via_region_selected_flag[i] ) { 3787_via_move_region(i, move_x, move_y); 3788} 3789} 3790} 3791 3792function _via_validate_move_region(x, y, canvas_attr) { 3793switch( canvas_attr['name'] ) { 3794case VIA_REGION_SHAPE.RECT: 3795// left and top boundary check 3796if (x < 0 || y < 0) { 3797show_message('Region moved beyond image boundary. Resetting.'); 3798return false; 3799} 3800// right and bottom boundary check 3801if ((y + canvas_attr['height']) > _via_current_image_height || 3802(x + canvas_attr['width']) > _via_current_image_width) { 3803show_message('Region moved beyond image boundary. Resetting.'); 3804return false; 3805} 3806 3807// same validation for all 3808case VIA_REGION_SHAPE.CIRCLE: 3809case VIA_REGION_SHAPE.ELLIPSE: 3810case VIA_REGION_SHAPE.POINT: 3811case VIA_REGION_SHAPE.POLYLINE: 3812case VIA_REGION_SHAPE.POLYGON: 3813if (x < 0 || y < 0 || 3814x > _via_current_image_width || y > _via_current_image_height) { 3815show_message('Region moved beyond image boundary. Resetting.'); 3816return false; 3817} 3818} 3819return true; 3820} 3821 3822function _via_move_region(region_id, move_x, move_y) { 3823var image_attr = _via_img_metadata[_via_image_id].regions[region_id].shape_attributes; 3824var canvas_attr = _via_canvas_regions[region_id].shape_attributes; 3825 3826switch( canvas_attr['name'] ) { 3827case VIA_REGION_SHAPE.RECT: 3828var xnew = image_attr['x'] + Math.round(move_x * _via_canvas_scale); 3829var ynew = image_attr['y'] + Math.round(move_y * _via_canvas_scale); 3830 3831var is_valid = _via_validate_move_region(xnew, ynew, image_attr); 3832if (! is_valid ) { break; } 3833 3834image_attr['x'] = xnew; 3835image_attr['y'] = ynew; 3836 3837canvas_attr['x'] = Math.round( image_attr['x'] / _via_canvas_scale); 3838canvas_attr['y'] = Math.round( image_attr['y'] / _via_canvas_scale); 3839break; 3840 3841case VIA_REGION_SHAPE.CIRCLE: // Fall-through 3842case VIA_REGION_SHAPE.ELLIPSE: // Fall-through 3843case VIA_REGION_SHAPE.POINT: 3844var cxnew = image_attr['cx'] + Math.round(move_x * _via_canvas_scale); 3845var cynew = image_attr['cy'] + Math.round(move_y * _via_canvas_scale); 3846 3847var is_valid = _via_validate_move_region(cxnew, cynew, image_attr); 3848if (! is_valid ) { break; } 3849 3850image_attr['cx'] = cxnew; 3851image_attr['cy'] = cynew; 3852 3853canvas_attr['cx'] = Math.round( image_attr['cx'] / _via_canvas_scale); 3854canvas_attr['cy'] = Math.round( image_attr['cy'] / _via_canvas_scale); 3855break; 3856 3857case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3858case VIA_REGION_SHAPE.POLYGON: 3859var img_px = image_attr['all_points_x']; 3860var img_py = image_attr['all_points_y']; 3861var canvas_px = canvas_attr['all_points_x']; 3862var canvas_py = canvas_attr['all_points_y']; 3863// clone for reverting if valiation fails 3864var img_px_old = Object.assign({}, img_px); 3865var img_py_old = Object.assign({}, img_py); 3866 3867// validate move 3868for (var i=0; i<img_px.length; ++i) { 3869var pxnew = img_px[i] + Math.round(move_x * _via_canvas_scale); 3870var pynew = img_py[i] + Math.round(move_y * _via_canvas_scale); 3871if (! _via_validate_move_region(pxnew, pynew, image_attr) ) { 3872img_px = img_px_old; 3873img_py = img_py_old; 3874break; 3875} 3876} 3877// move points 3878for (var i=0; i<img_px.length; ++i) { 3879img_px[i] = img_px[i] + Math.round(move_x * _via_canvas_scale); 3880img_py[i] = img_py[i] + Math.round(move_y * _via_canvas_scale); 3881} 3882 3883for (var i=0; i<canvas_px.length; ++i) { 3884canvas_px[i] = Math.round( img_px[i] / _via_canvas_scale ); 3885canvas_py[i] = Math.round( img_py[i] / _via_canvas_scale ); 3886} 3887break; 3888} 3889} 3890 3891function _via_polygon_del_vertex(region_id, vertex_id) { 3892var rs = _via_canvas_regions[region_id].shape_attributes; 3893var npts = rs['all_points_x'].length; 3894var shape = rs['name']; 3895if ( shape !== VIA_REGION_SHAPE.POLYGON && shape !== VIA_REGION_SHAPE.POLYLINE ) { 3896show_message('Vertices can only be deleted from polygon/polyline.'); 3897return false; 3898} 3899if ( npts <=3 && shape === VIA_REGION_SHAPE.POLYGON ) { 3900show_message('Failed to delete vertex because a polygon must have at least 3 vertices.'); 3901return false; 3902} 3903if ( npts <=2 && shape === VIA_REGION_SHAPE.POLYLINE ) { 3904show_message('Failed to delete vertex because a polyline must have at least 2 vertices.'); 3905return false; 3906} 3907// delete vertex from canvas 3908_via_canvas_regions[region_id].shape_attributes['all_points_x'].splice(vertex_id, 1); 3909_via_canvas_regions[region_id].shape_attributes['all_points_y'].splice(vertex_id, 1); 3910 3911// delete vertex from image metadata 3912_via_img_metadata[_via_image_id].regions[region_id].shape_attributes['all_points_x'].splice(vertex_id, 1); 3913_via_img_metadata[_via_image_id].regions[region_id].shape_attributes['all_points_y'].splice(vertex_id, 1); 3914return true; 3915} 3916 3917// 3918// Canvas update routines 3919// 3920function _via_redraw_reg_canvas() { 3921if (_via_current_image_loaded) { 3922_via_reg_ctx.clearRect(0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 3923if ( _via_canvas_regions.length > 0 ) { 3924if (_via_is_region_boundary_visible) { 3925draw_all_regions(); 3926} 3927if (_via_is_region_id_visible) { 3928draw_all_region_id(); 3929} 3930} 3931} 3932} 3933 3934function _via_clear_reg_canvas() { 3935_via_reg_ctx.clearRect(0, 0, _via_reg_canvas.width, _via_reg_canvas.height); 3936} 3937 3938function draw_all_regions() { 3939var aid = _via_settings.ui.image.region_color; 3940var attr, is_selected, aid, avalue; 3941for (var i=0; i < _via_canvas_regions.length; ++i) { 3942attr = _via_canvas_regions[i].shape_attributes; 3943is_selected = _via_region_selected_flag[i]; 3944 3945// region stroke style may depend on attribute value 3946_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_FILL_COLOR; 3947if ( ! _via_is_user_drawing_polygon && 3948aid !== '__via_default_region_color__' ) { 3949avalue = _via_img_metadata[_via_image_id].regions[i].region_attributes[aid]; 3950if ( _via_canvas_regions_group_color.hasOwnProperty(avalue) ) { 3951_via_reg_ctx.strokeStyle = _via_canvas_regions_group_color[avalue]; 3952} 3953} 3954 3955switch( attr['name'] ) { 3956case VIA_REGION_SHAPE.RECT: 3957_via_draw_rect_region(attr['x'], 3958attr['y'], 3959attr['width'], 3960attr['height'], 3961is_selected); 3962break; 3963 3964case VIA_REGION_SHAPE.CIRCLE: 3965_via_draw_circle_region(attr['cx'], 3966attr['cy'], 3967attr['r'], 3968is_selected); 3969break; 3970 3971case VIA_REGION_SHAPE.ELLIPSE: 3972if (typeof(attr['theta']) === 'undefined') { attr['theta'] = 0; } 3973_via_draw_ellipse_region(attr['cx'], 3974attr['cy'], 3975attr['rx'], 3976attr['ry'], 3977attr['theta'], 3978is_selected); 3979break; 3980 3981case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 3982case VIA_REGION_SHAPE.POLYGON: 3983_via_draw_polygon_region(attr['all_points_x'], 3984attr['all_points_y'], 3985is_selected, 3986attr['name']); 3987break; 3988 3989case VIA_REGION_SHAPE.POINT: 3990_via_draw_point_region(attr['cx'], 3991attr['cy'], 3992is_selected); 3993break; 3994} 3995} 3996} 3997 3998// control point for resize of region boundaries 3999function _via_draw_control_point(cx, cy) { 4000_via_reg_ctx.beginPath(); 4001_via_reg_ctx.arc(cx, cy, VIA_REGION_SHAPES_POINTS_RADIUS, 0, 2*Math.PI, false); 4002_via_reg_ctx.closePath(); 4003 4004_via_reg_ctx.fillStyle = VIA_THEME_CONTROL_POINT_COLOR; 4005_via_reg_ctx.globalAlpha = 1.0; 4006_via_reg_ctx.fill(); 4007} 4008 4009function _via_draw_rect_region(x, y, w, h, is_selected) { 4010if (is_selected) { 4011_via_draw_rect(x, y, w, h); 4012 4013_via_reg_ctx.strokeStyle = VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR; 4014_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4015_via_reg_ctx.stroke(); 4016 4017_via_reg_ctx.fillStyle = VIA_THEME_SEL_REGION_FILL_COLOR; 4018_via_reg_ctx.globalAlpha = VIA_THEME_SEL_REGION_OPACITY; 4019_via_reg_ctx.fill(); 4020_via_reg_ctx.globalAlpha = 1.0; 4021 4022_via_draw_control_point(x , y); 4023_via_draw_control_point(x+w, y+h); 4024_via_draw_control_point(x , y+h); 4025_via_draw_control_point(x+w, y); 4026_via_draw_control_point(x+w/2, y); 4027_via_draw_control_point(x+w/2, y+h); 4028_via_draw_control_point(x , y+h/2); 4029_via_draw_control_point(x+w , y+h/2); 4030} else { 4031// draw a fill line 4032_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4033_via_draw_rect(x, y, w, h); 4034_via_reg_ctx.stroke(); 4035 4036if ( w > VIA_THEME_REGION_BOUNDARY_WIDTH && 4037h > VIA_THEME_REGION_BOUNDARY_WIDTH ) { 4038// draw a boundary line on both sides of the fill line 4039_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_LINE_COLOR; 4040_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/4; 4041_via_draw_rect(x - VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4042y - VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4043w + VIA_THEME_REGION_BOUNDARY_WIDTH, 4044h + VIA_THEME_REGION_BOUNDARY_WIDTH); 4045_via_reg_ctx.stroke(); 4046 4047_via_draw_rect(x + VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4048y + VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4049w - VIA_THEME_REGION_BOUNDARY_WIDTH, 4050h - VIA_THEME_REGION_BOUNDARY_WIDTH); 4051_via_reg_ctx.stroke(); 4052} 4053} 4054} 4055 4056function _via_draw_rect(x, y, w, h) { 4057_via_reg_ctx.beginPath(); 4058_via_reg_ctx.moveTo(x , y); 4059_via_reg_ctx.lineTo(x+w, y); 4060_via_reg_ctx.lineTo(x+w, y+h); 4061_via_reg_ctx.lineTo(x , y+h); 4062_via_reg_ctx.closePath(); 4063} 4064 4065function _via_draw_circle_region(cx, cy, r, is_selected) { 4066if (is_selected) { 4067_via_draw_circle(cx, cy, r); 4068 4069_via_reg_ctx.strokeStyle = VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR; 4070_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4071_via_reg_ctx.stroke(); 4072 4073_via_reg_ctx.fillStyle = VIA_THEME_SEL_REGION_FILL_COLOR; 4074_via_reg_ctx.globalAlpha = VIA_THEME_SEL_REGION_OPACITY; 4075_via_reg_ctx.fill(); 4076_via_reg_ctx.globalAlpha = 1.0; 4077 4078_via_draw_control_point(cx + r, cy); 4079} else { 4080// draw a fill line 4081_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4082_via_draw_circle(cx, cy, r); 4083_via_reg_ctx.stroke(); 4084 4085if ( r > VIA_THEME_REGION_BOUNDARY_WIDTH ) { 4086// draw a boundary line on both sides of the fill line 4087_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_LINE_COLOR; 4088_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/4; 4089_via_draw_circle(cx, cy, 4090r - VIA_THEME_REGION_BOUNDARY_WIDTH/2); 4091_via_reg_ctx.stroke(); 4092_via_draw_circle(cx, cy, 4093r + VIA_THEME_REGION_BOUNDARY_WIDTH/2); 4094_via_reg_ctx.stroke(); 4095} 4096} 4097} 4098 4099function _via_draw_circle(cx, cy, r) { 4100_via_reg_ctx.beginPath(); 4101_via_reg_ctx.arc(cx, cy, r, 0, 2*Math.PI, false); 4102_via_reg_ctx.closePath(); 4103} 4104 4105function _via_draw_ellipse_region(cx, cy, rx, ry, rr, is_selected) { 4106if (is_selected) { 4107_via_draw_ellipse(cx, cy, rx, ry, rr); 4108 4109_via_reg_ctx.strokeStyle = VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR; 4110_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4111_via_reg_ctx.stroke(); 4112 4113_via_reg_ctx.fillStyle = VIA_THEME_SEL_REGION_FILL_COLOR; 4114_via_reg_ctx.globalAlpha = VIA_THEME_SEL_REGION_OPACITY; 4115_via_reg_ctx.fill(); 4116_via_reg_ctx.globalAlpha = 1.0; 4117 4118_via_draw_control_point(cx + rx * Math.cos(rr), cy + rx * Math.sin(rr)); 4119_via_draw_control_point(cx - rx * Math.cos(rr), cy - rx * Math.sin(rr)); 4120_via_draw_control_point(cx + ry * Math.sin(rr), cy - ry * Math.cos(rr)); 4121_via_draw_control_point(cx - ry * Math.sin(rr), cy + ry * Math.cos(rr)); 4122 4123} else { 4124// draw a fill line 4125_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4126_via_draw_ellipse(cx, cy, rx, ry, rr); 4127_via_reg_ctx.stroke(); 4128 4129if ( rx > VIA_THEME_REGION_BOUNDARY_WIDTH && 4130ry > VIA_THEME_REGION_BOUNDARY_WIDTH ) { 4131// draw a boundary line on both sides of the fill line 4132_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_LINE_COLOR; 4133_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/4; 4134_via_draw_ellipse(cx, cy, 4135rx + VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4136ry + VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4137rr); 4138_via_reg_ctx.stroke(); 4139_via_draw_ellipse(cx, cy, 4140rx - VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4141ry - VIA_THEME_REGION_BOUNDARY_WIDTH/2, 4142rr); 4143_via_reg_ctx.stroke(); 4144} 4145} 4146} 4147 4148function _via_draw_ellipse(cx, cy, rx, ry, rr) { 4149_via_reg_ctx.save(); 4150 4151_via_reg_ctx.beginPath(); 4152_via_reg_ctx.ellipse(cx, cy, rx, ry, rr, 0, 2 * Math.PI); 4153 4154_via_reg_ctx.restore(); // restore to original state 4155_via_reg_ctx.closePath(); 4156} 4157 4158function _via_draw_polygon_region(all_points_x, all_points_y, is_selected, shape) { 4159if ( is_selected ) { 4160_via_reg_ctx.strokeStyle = VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR; 4161_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4162_via_reg_ctx.beginPath(); 4163_via_reg_ctx.moveTo(all_points_x[0], all_points_y[0]); 4164for ( var i=1; i < all_points_x.length; ++i ) { 4165_via_reg_ctx.lineTo(all_points_x[i], all_points_y[i]); 4166} 4167if ( shape === VIA_REGION_SHAPE.POLYGON ) { 4168_via_reg_ctx.lineTo(all_points_x[0], all_points_y[0]); // close loop 4169} 4170_via_reg_ctx.stroke(); 4171 4172_via_reg_ctx.fillStyle = VIA_THEME_SEL_REGION_FILL_COLOR; 4173_via_reg_ctx.globalAlpha = VIA_THEME_SEL_REGION_OPACITY; 4174_via_reg_ctx.fill(); 4175_via_reg_ctx.globalAlpha = 1.0; 4176for ( var i=0; i < all_points_x.length; ++i ) { 4177_via_draw_control_point(all_points_x[i], all_points_y[i]); 4178} 4179} else { 4180// draw a fill line 4181_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4182_via_reg_ctx.beginPath(); 4183_via_reg_ctx.moveTo(all_points_x[0], all_points_y[0]); 4184for ( var i=0; i < all_points_x.length; ++i ) { 4185_via_reg_ctx.lineTo(all_points_x[i], all_points_y[i]); 4186} 4187if ( shape === VIA_REGION_SHAPE.POLYGON ) { 4188_via_reg_ctx.lineTo(all_points_x[0], all_points_y[0]); // close loop 4189} 4190_via_reg_ctx.stroke(); 4191} 4192} 4193 4194function _via_draw_point_region(cx, cy, is_selected) { 4195if (is_selected) { 4196_via_draw_point(cx, cy, VIA_REGION_POINT_RADIUS); 4197 4198_via_reg_ctx.strokeStyle = VIA_THEME_SEL_REGION_FILL_BOUNDARY_COLOR; 4199_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4200_via_reg_ctx.stroke(); 4201 4202_via_reg_ctx.fillStyle = VIA_THEME_SEL_REGION_FILL_COLOR; 4203_via_reg_ctx.globalAlpha = VIA_THEME_SEL_REGION_OPACITY; 4204_via_reg_ctx.fill(); 4205_via_reg_ctx.globalAlpha = 1.0; 4206} else { 4207// draw a fill line 4208_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/2; 4209_via_draw_point(cx, cy, VIA_REGION_POINT_RADIUS); 4210_via_reg_ctx.stroke(); 4211 4212// draw a boundary line on both sides of the fill line 4213_via_reg_ctx.strokeStyle = VIA_THEME_BOUNDARY_LINE_COLOR; 4214_via_reg_ctx.lineWidth = VIA_THEME_REGION_BOUNDARY_WIDTH/4; 4215_via_draw_point(cx, cy, 4216VIA_REGION_POINT_RADIUS - VIA_THEME_REGION_BOUNDARY_WIDTH/2); 4217_via_reg_ctx.stroke(); 4218_via_draw_point(cx, cy, 4219VIA_REGION_POINT_RADIUS + VIA_THEME_REGION_BOUNDARY_WIDTH/2); 4220_via_reg_ctx.stroke(); 4221} 4222} 4223 4224function _via_draw_point(cx, cy, r) { 4225_via_reg_ctx.beginPath(); 4226_via_reg_ctx.arc(cx, cy, r, 0, 2*Math.PI, false); 4227_via_reg_ctx.closePath(); 4228} 4229 4230function draw_all_region_id() { 4231_via_reg_ctx.shadowColor = "transparent"; 4232_via_reg_ctx.font = _via_settings.ui.image.region_label_font; 4233for ( var i = 0; i < _via_img_metadata[_via_image_id].regions.length; ++i ) { 4234var canvas_reg = _via_canvas_regions[i]; 4235 4236var bbox = get_region_bounding_box(canvas_reg); 4237var x = bbox[0]; 4238var y = bbox[1]; 4239var w = Math.abs(bbox[2] - bbox[0]); 4240 4241var char_width = _via_reg_ctx.measureText('M').width; 4242var char_height = 1.8 * char_width; 4243 4244var annotation_str = (i+1).toString(); 4245var rattr = _via_img_metadata[_via_image_id].regions[i].region_attributes[_via_settings.ui.image.region_label]; 4246var rshape = _via_img_metadata[_via_image_id].regions[i].shape_attributes['name']; 4247if ( _via_settings.ui.image.region_label !== '__via_region_id__' ) { 4248if ( typeof(rattr) !== 'undefined' ) { 4249switch( typeof(rattr) ) { 4250default: 4251case 'string': 4252annotation_str = rattr; 4253break; 4254case 'object': 4255annotation_str = Object.keys(rattr).join(','); 4256break; 4257} 4258} else { 4259annotation_str = 'undefined'; 4260} 4261} 4262 4263var bgnd_rect_width; 4264var strw = _via_reg_ctx.measureText(annotation_str).width; 4265if ( strw > w ) { 4266if ( _via_settings.ui.image.region_label === '__via_region_id__' ) { 4267// region-id is always visible in full 4268bgnd_rect_width = strw + char_width; 4269} else { 4270 4271// if text overflows, crop it 4272var str_max = Math.floor((w * annotation_str.length) / strw); 4273if ( str_max > 1 ) { 4274annotation_str = annotation_str.substr(0, str_max-1) + '.'; 4275bgnd_rect_width = w; 4276} else { 4277annotation_str = annotation_str.substr(0, 1) + '.'; 4278bgnd_rect_width = 2 * char_width; 4279} 4280} 4281} else { 4282bgnd_rect_width = strw + char_width; 4283} 4284 4285if (canvas_reg.shape_attributes['name'] === VIA_REGION_SHAPE.POLYGON || 4286canvas_reg.shape_attributes['name'] === VIA_REGION_SHAPE.POLYLINE) { 4287// put label near the first vertex 4288x = canvas_reg.shape_attributes['all_points_x'][0]; 4289y = canvas_reg.shape_attributes['all_points_y'][0]; 4290} else { 4291// center the label 4292x = x - (bgnd_rect_width/2 - w/2); 4293} 4294 4295// ensure that the text is within the image boundaries 4296if ( y < char_height ) { 4297y = char_height; 4298} 4299 4300// first, draw a background rectangle first 4301_via_reg_ctx.fillStyle = 'black'; 4302_via_reg_ctx.globalAlpha = 0.8; 4303_via_reg_ctx.fillRect(Math.floor(x), 4304Math.floor(y - 1.1*char_height), 4305Math.floor(bgnd_rect_width), 4306Math.floor(char_height)); 4307 4308// then, draw text over this background rectangle 4309_via_reg_ctx.globalAlpha = 1.0; 4310_via_reg_ctx.fillStyle = 'yellow'; 4311_via_reg_ctx.fillText(annotation_str, 4312Math.floor(x + 0.4*char_width), 4313Math.floor(y - 0.35*char_height)); 4314 4315} 4316} 4317 4318function get_region_bounding_box(region) { 4319var d = region.shape_attributes; 4320var bbox = new Array(4); 4321 4322switch( d['name'] ) { 4323case 'rect': 4324bbox[0] = d['x']; 4325bbox[1] = d['y']; 4326bbox[2] = d['x'] + d['width']; 4327bbox[3] = d['y'] + d['height']; 4328break; 4329 4330case 'circle': 4331bbox[0] = d['cx'] - d['r']; 4332bbox[1] = d['cy'] - d['r']; 4333bbox[2] = d['cx'] + d['r']; 4334bbox[3] = d['cy'] + d['r']; 4335break; 4336 4337case 'ellipse': 4338let radians = d['theta']; 4339let radians90 = radians + Math.PI / 2; 4340let ux = d['rx'] * Math.cos(radians); 4341let uy = d['rx'] * Math.sin(radians); 4342let vx = d['ry'] * Math.cos(radians90); 4343let vy = d['ry'] * Math.sin(radians90); 4344 4345let width = Math.sqrt(ux * ux + vx * vx) * 2; 4346let height = Math.sqrt(uy * uy + vy * vy) * 2; 4347 4348bbox[0] = d['cx'] - (width / 2); 4349bbox[1] = d['cy'] - (height / 2); 4350bbox[2] = d['cx'] + (width / 2); 4351bbox[3] = d['cy'] + (height / 2); 4352break; 4353 4354case 'polyline': // handled by polygon 4355case 'polygon': 4356var all_points_x = d['all_points_x']; 4357var all_points_y = d['all_points_y']; 4358 4359var minx = Number.MAX_SAFE_INTEGER; 4360var miny = Number.MAX_SAFE_INTEGER; 4361var maxx = 0; 4362var maxy = 0; 4363for ( var i=0; i < all_points_x.length; ++i ) { 4364if ( all_points_x[i] < minx ) { 4365minx = all_points_x[i]; 4366} 4367if ( all_points_x[i] > maxx ) { 4368maxx = all_points_x[i]; 4369} 4370if ( all_points_y[i] < miny ) { 4371miny = all_points_y[i]; 4372} 4373if ( all_points_y[i] > maxy ) { 4374maxy = all_points_y[i]; 4375} 4376} 4377bbox[0] = minx; 4378bbox[1] = miny; 4379bbox[2] = maxx; 4380bbox[3] = maxy; 4381break; 4382 4383case 'point': 4384bbox[0] = d['cx'] - VIA_REGION_POINT_RADIUS; 4385bbox[1] = d['cy'] - VIA_REGION_POINT_RADIUS; 4386bbox[2] = d['cx'] + VIA_REGION_POINT_RADIUS; 4387bbox[3] = d['cy'] + VIA_REGION_POINT_RADIUS; 4388break; 4389} 4390return bbox; 4391} 4392 4393// 4394// Region collision routines 4395// 4396function is_inside_region(px, py, descending_order) { 4397var N = _via_canvas_regions.length; 4398if ( N === 0 ) { 4399return -1; 4400} 4401var start, end, del; 4402// traverse the canvas regions in alternating ascending 4403// and descending order to solve the issue of nested regions 4404if ( descending_order ) { 4405start = N - 1; 4406end = -1; 4407del = -1; 4408} else { 4409start = 0; 4410end = N; 4411del = 1; 4412} 4413 4414var i = start; 4415while ( i !== end ) { 4416var yes = is_inside_this_region(px, py, i); 4417if (yes) { 4418return i; 4419} 4420i = i + del; 4421} 4422return -1; 4423} 4424 4425function is_inside_this_region(px, py, region_id) { 4426var attr = _via_canvas_regions[region_id].shape_attributes; 4427var result = false; 4428switch ( attr['name'] ) { 4429case VIA_REGION_SHAPE.RECT: 4430result = is_inside_rect(attr['x'], 4431attr['y'], 4432attr['width'], 4433attr['height'], 4434px, py); 4435break; 4436 4437case VIA_REGION_SHAPE.CIRCLE: 4438result = is_inside_circle(attr['cx'], 4439attr['cy'], 4440attr['r'], 4441px, py); 4442break; 4443 4444case VIA_REGION_SHAPE.ELLIPSE: 4445result = is_inside_ellipse(attr['cx'], 4446attr['cy'], 4447attr['rx'], 4448attr['ry'], 4449attr['theta'], 4450px, py); 4451break; 4452 4453case VIA_REGION_SHAPE.POLYLINE: // handled by POLYGON 4454case VIA_REGION_SHAPE.POLYGON: 4455result = is_inside_polygon(attr['all_points_x'], 4456attr['all_points_y'], 4457px, py); 4458break; 4459 4460case VIA_REGION_SHAPE.POINT: 4461result = is_inside_point(attr['cx'], 4462attr['cy'], 4463px, py); 4464break; 4465} 4466return result; 4467} 4468 4469function is_inside_circle(cx, cy, r, px, py) { 4470var dx = px - cx; 4471var dy = py - cy; 4472return (dx * dx + dy * dy) < r * r; 4473} 4474 4475function is_inside_rect(x, y, w, h, px, py) { 4476return px > x && 4477px < (x + w) && 4478py > y && 4479py < (y + h); 4480} 4481 4482function is_inside_ellipse(cx, cy, rx, ry, rr, px, py) { 4483// Inverse rotation of pixel coordinates 4484var dx = Math.cos(-rr) * (cx - px) - Math.sin(-rr) * (cy - py) 4485var dy = Math.sin(-rr) * (cx - px) + Math.cos(-rr) * (cy - py) 4486 4487return ((dx * dx) / (rx * rx)) + ((dy * dy) / (ry * ry)) < 1; 4488} 4489 4490// returns 0 when (px,py) is outside the polygon 4491// source: http://geomalgorithms.com/a03-_inclusion.html 4492function is_inside_polygon(all_points_x, all_points_y, px, py) { 4493if ( all_points_x.length === 0 || all_points_y.length === 0 ) { 4494return 0; 4495} 4496 4497var wn = 0; // the winding number counter 4498var n = all_points_x.length; 4499var i; 4500// loop through all edges of the polygon 4501for ( i = 0; i < n-1; ++i ) { // edge from V[i] to V[i+1] 4502var is_left_value = is_left( all_points_x[i], all_points_y[i], 4503all_points_x[i+1], all_points_y[i+1], 4504px, py); 4505 4506if (all_points_y[i] <= py) { 4507if (all_points_y[i+1] > py && is_left_value > 0) { 4508++wn; 4509} 4510} 4511else { 4512if (all_points_y[i+1] <= py && is_left_value < 0) { 4513--wn; 4514} 4515} 4516} 4517 4518// also take into account the loop closing edge that connects last point with first point 4519var is_left_value = is_left( all_points_x[n-1], all_points_y[n-1], 4520all_points_x[0], all_points_y[0], 4521px, py); 4522 4523if (all_points_y[n-1] <= py) { 4524if (all_points_y[0] > py && is_left_value > 0) { 4525++wn; 4526} 4527} 4528else { 4529if (all_points_y[0] <= py && is_left_value < 0) { 4530--wn; 4531} 4532} 4533 4534if ( wn === 0 ) { 4535return 0; 4536} 4537else { 4538return 1; 4539} 4540} 4541 4542function is_inside_point(cx, cy, px, py) { 4543var dx = px - cx; 4544var dy = py - cy; 4545var r2 = VIA_POLYGON_VERTEX_MATCH_TOL * VIA_POLYGON_VERTEX_MATCH_TOL; 4546return (dx * dx + dy * dy) < r2; 4547} 4548 4549// returns 4550// >0 if (x2,y2) lies on the left side of line joining (x0,y0) and (x1,y1) 4551// =0 if (x2,y2) lies on the line joining (x0,y0) and (x1,y1) 4552// >0 if (x2,y2) lies on the right side of line joining (x0,y0) and (x1,y1) 4553// source: http://geomalgorithms.com/a03-_inclusion.html 4554function is_left(x0, y0, x1, y1, x2, y2) { 4555return ( ((x1 - x0) * (y2 - y0)) - ((x2 - x0) * (y1 - y0)) ); 4556} 4557 4558function is_on_region_corner(px, py) { 4559var _via_region_edge = [-1, -1]; // region_id, corner_id [top-left=1,top-right=2,bottom-right=3,bottom-left=4] 4560 4561for ( var i = 0; i < _via_canvas_regions.length; ++i ) { 4562var attr = _via_canvas_regions[i].shape_attributes; 4563var result = false; 4564_via_region_edge[0] = i; 4565 4566switch ( attr['name'] ) { 4567case VIA_REGION_SHAPE.RECT: 4568result = is_on_rect_edge(attr['x'], 4569attr['y'], 4570attr['width'], 4571attr['height'], 4572px, py); 4573break; 4574 4575case VIA_REGION_SHAPE.CIRCLE: 4576result = is_on_circle_edge(attr['cx'], 4577attr['cy'], 4578attr['r'], 4579px, py); 4580break; 4581 4582case VIA_REGION_SHAPE.ELLIPSE: 4583result = is_on_ellipse_edge(attr['cx'], 4584attr['cy'], 4585attr['rx'], 4586attr['ry'], 4587attr['theta'], 4588px, py); 4589break; 4590 4591case VIA_REGION_SHAPE.POLYLINE: // handled by polygon 4592case VIA_REGION_SHAPE.POLYGON: 4593result = is_on_polygon_vertex(attr['all_points_x'], 4594attr['all_points_y'], 4595px, py); 4596if ( result === 0 ) { 4597result = is_on_polygon_edge(attr['all_points_x'], 4598attr['all_points_y'], 4599px, py); 4600} 4601break; 4602 4603case VIA_REGION_SHAPE.POINT: 4604// since there are no edges of a point 4605result = 0; 4606break; 4607} 4608 4609if (result > 0) { 4610_via_region_edge[1] = result; 4611return _via_region_edge; 4612} 4613} 4614_via_region_edge[0] = -1; 4615return _via_region_edge; 4616} 4617 4618function is_on_rect_edge(x, y, w, h, px, py) { 4619var dx0 = Math.abs(x - px); 4620var dy0 = Math.abs(y - py); 4621var dx1 = Math.abs(x + w - px); 4622var dy1 = Math.abs(y + h - py); 4623//[top-left=1,top-right=2,bottom-right=3,bottom-left=4] 4624if ( dx0 < VIA_REGION_EDGE_TOL && 4625dy0 < VIA_REGION_EDGE_TOL ) { 4626return 1; 4627} 4628if ( dx1 < VIA_REGION_EDGE_TOL && 4629dy0 < VIA_REGION_EDGE_TOL ) { 4630return 2; 4631} 4632if ( dx1 < VIA_REGION_EDGE_TOL && 4633dy1 < VIA_REGION_EDGE_TOL ) { 4634return 3; 4635} 4636 4637if ( dx0 < VIA_REGION_EDGE_TOL && 4638dy1 < VIA_REGION_EDGE_TOL ) { 4639return 4; 4640} 4641 4642var mx0 = Math.abs(x + w/2 - px); 4643var my0 = Math.abs(y + h/2 - py); 4644//[top-middle=5,right-middle=6,bottom-middle=7,left-middle=8] 4645if ( mx0 < VIA_REGION_EDGE_TOL && 4646dy0 < VIA_REGION_EDGE_TOL ) { 4647return 5; 4648} 4649if ( dx1 < VIA_REGION_EDGE_TOL && 4650my0 < VIA_REGION_EDGE_TOL ) { 4651return 6; 4652} 4653if ( mx0 < VIA_REGION_EDGE_TOL && 4654dy1 < VIA_REGION_EDGE_TOL ) { 4655return 7; 4656} 4657if ( dx0 < VIA_REGION_EDGE_TOL && 4658my0 < VIA_REGION_EDGE_TOL ) { 4659return 8; 4660} 4661 4662return 0; 4663} 4664 4665function is_on_circle_edge(cx, cy, r, px, py) { 4666var dx = cx - px; 4667var dy = cy - py; 4668if ( Math.abs(Math.sqrt( dx*dx + dy*dy ) - r) < VIA_REGION_EDGE_TOL ) { 4669var theta = Math.atan2( py - cy, px - cx ); 4670if ( Math.abs(theta - (Math.PI/2)) < VIA_THETA_TOL || 4671Math.abs(theta + (Math.PI/2)) < VIA_THETA_TOL) { 4672return 5; 4673} 4674if ( Math.abs(theta) < VIA_THETA_TOL || 4675Math.abs(Math.abs(theta) - Math.PI) < VIA_THETA_TOL) { 4676return 6; 4677} 4678 4679if ( theta > 0 && theta < (Math.PI/2) ) { 4680return 1; 4681} 4682if ( theta > (Math.PI/2) && theta < (Math.PI) ) { 4683return 4; 4684} 4685if ( theta < 0 && theta > -(Math.PI/2) ) { 4686return 2; 4687} 4688if ( theta < -(Math.PI/2) && theta > -Math.PI ) { 4689return 3; 4690} 4691} else { 4692return 0; 4693} 4694} 4695 4696function is_on_ellipse_edge(cx, cy, rx, ry, rr, px, py) { 4697// Inverse rotation of pixel coordinates 4698px = px - cx; 4699py = py - cy; 4700var px_ = Math.cos(-rr) * px - Math.sin(-rr) * py; 4701var py_ = Math.sin(-rr) * px + Math.cos(-rr) * py; 4702px = px_ + cx; 4703py = py_ + cy; 4704 4705var dx = (cx - px)/rx; 4706var dy = (cy - py)/ry; 4707 4708if ( Math.abs(Math.sqrt( dx*dx + dy*dy ) - 1) < VIA_ELLIPSE_EDGE_TOL ) { 4709var theta = Math.atan2( py - cy, px - cx ); 4710if ( Math.abs(theta - (Math.PI/2)) < VIA_THETA_TOL || 4711Math.abs(theta + (Math.PI/2)) < VIA_THETA_TOL) { 4712return 5; 4713} 4714if ( Math.abs(theta) < VIA_THETA_TOL || 4715Math.abs(Math.abs(theta) - Math.PI) < VIA_THETA_TOL) { 4716return 6; 4717} 4718} else { 4719return 0; 4720} 4721} 4722 4723function is_on_polygon_vertex(all_points_x, all_points_y, px, py) { 4724var i, n; 4725n = all_points_x.length; 4726 4727for ( i = 0; i < n; ++i ) { 4728if ( Math.abs(all_points_x[i] - px) < VIA_POLYGON_VERTEX_MATCH_TOL && 4729Math.abs(all_points_y[i] - py) < VIA_POLYGON_VERTEX_MATCH_TOL ) { 4730return (VIA_POLYGON_RESIZE_VERTEX_OFFSET+i); 4731} 4732} 4733return 0; 4734} 4735 4736function is_on_polygon_edge(all_points_x, all_points_y, px, py) { 4737var i, n, di, d; 4738n = all_points_x.length; 4739d = []; 4740for ( i = 0; i < n - 1; ++i ) { 4741di = dist_to_line(px, py, all_points_x[i], all_points_y[i], all_points_x[i+1], all_points_y[i+1]); 4742d.push(di); 4743} 4744// closing edge 4745di = dist_to_line(px, py, all_points_x[n-1], all_points_y[n-1], all_points_x[0], all_points_y[0]); 4746d.push(di); 4747 4748var smallest_value = d[0]; 4749var smallest_index = 0; 4750n = d.length; 4751for ( i = 1; i < n; ++i ) { 4752if ( d[i] < smallest_value ) { 4753smallest_value = d[i]; 4754smallest_index = i; 4755} 4756} 4757if ( smallest_value < VIA_POLYGON_VERTEX_MATCH_TOL ) { 4758return (VIA_POLYGON_RESIZE_VERTEX_OFFSET + smallest_index); 4759} else { 4760return 0; 4761} 4762} 4763 4764function is_point_inside_bounding_box(x, y, x1, y1, x2, y2) { 4765// ensure that (x1,y1) is top left and (x2,y2) is bottom right corner of rectangle 4766var rect = {}; 4767if( x1 < x2 ) { 4768rect.x1 = x1; 4769rect.x2 = x2; 4770} else { 4771rect.x1 = x2; 4772rect.x2 = x1; 4773} 4774if ( y1 < y2 ) { 4775rect.y1 = y1; 4776rect.y2 = y2; 4777} else { 4778rect.y1 = y2; 4779rect.y2 = y1; 4780} 4781 4782if ( x >= rect.x1 && x <= rect.x2 && y >= rect.y1 && y <= rect.y2 ) { 4783return true; 4784} else { 4785return false; 4786} 4787} 4788 4789function dist_to_line(x, y, x1, y1, x2, y2) { 4790if ( is_point_inside_bounding_box(x, y, x1, y1, x2, y2) ) { 4791var dy = y2 - y1; 4792var dx = x2 - x1; 4793var nr = Math.abs( dy*x - dx*y + x2*y1 - y2*x1 ); 4794var dr = Math.sqrt( dx*dx + dy*dy ); 4795var dist = nr / dr; 4796return Math.round(dist); 4797} else { 4798return Number.MAX_SAFE_INTEGER; 4799} 4800} 4801 4802function rect_standardize_coordinates(d) { 4803// d[x0,y0,x1,y1] 4804// ensures that (d[0],d[1]) is top-left corner while 4805// (d[2],d[3]) is bottom-right corner 4806if ( d[0] > d[2] ) { 4807// swap 4808var t = d[0]; 4809d[0] = d[2]; 4810d[2] = t; 4811} 4812 4813if ( d[1] > d[3] ) { 4814// swap 4815var t = d[1]; 4816d[1] = d[3]; 4817d[3] = t; 4818} 4819} 4820 4821function rect_update_corner(corner_id, d, x, y, preserve_aspect_ratio) { 4822// pre-condition : d[x0,y0,x1,y1] is standardized 4823// post-condition : corner is moved ( d may not stay standardized ) 4824if (preserve_aspect_ratio) { 4825switch(corner_id) { 4826case 1: // Fall-through // top-left 4827case 3: // bottom-right 4828var dx = d[2] - d[0]; 4829var dy = d[3] - d[1]; 4830var norm = Math.sqrt( dx*dx + dy*dy ); 4831var nx = dx / norm; // x component of unit vector along the diagonal of rect 4832var ny = dy / norm; // y component 4833var proj = (x - d[0]) * nx + (y - d[1]) * ny; 4834var proj_x = nx * proj; 4835var proj_y = ny * proj; 4836// constrain (mx,my) to lie on a line connecting (x0,y0) and (x1,y1) 4837x = Math.round( d[0] + proj_x ); 4838y = Math.round( d[1] + proj_y ); 4839break; 4840 4841case 2: // Fall-through // top-right 4842case 4: // bottom-left 4843var dx = d[2] - d[0]; 4844var dy = d[1] - d[3]; 4845var norm = Math.sqrt( dx*dx + dy*dy ); 4846var nx = dx / norm; // x component of unit vector along the diagonal of rect 4847var ny = dy / norm; // y component 4848var proj = (x - d[0]) * nx + (y - d[3]) * ny; 4849var proj_x = nx * proj; 4850var proj_y = ny * proj; 4851// constrain (mx,my) to lie on a line connecting (x0,y0) and (x1,y1) 4852x = Math.round( d[0] + proj_x ); 4853y = Math.round( d[3] + proj_y ); 4854break; 4855} 4856} 4857 4858switch(corner_id) { 4859case 1: // top-left 4860d[0] = x; 4861d[1] = y; 4862break; 4863 4864case 3: // bottom-right 4865d[2] = x; 4866d[3] = y; 4867break; 4868 4869case 2: // top-right 4870d[2] = x; 4871d[1] = y; 4872break; 4873 4874case 4: // bottom-left 4875d[0] = x; 4876d[3] = y; 4877break; 4878 4879case 5: // top-middle 4880d[1] = y; 4881break; 4882 4883case 6: // right-middle 4884d[2] = x; 4885break; 4886 4887case 7: // bottom-middle 4888d[3] = y; 4889break; 4890 4891case 8: // left-middle 4892d[0] = x; 4893break; 4894} 4895} 4896 4897function _via_update_ui_components() { 4898if ( ! _via_current_image_loaded ) { 4899return; 4900} 4901 4902show_message('Updating user interface components.'); 4903switch(_via_display_area_content_name) { 4904case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID: 4905image_grid_set_content_panel_height_fixed(); 4906image_grid_set_content_to_current_group(); 4907break; 4908case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE: 4909if ( !_via_is_window_resized && _via_current_image_loaded ) { 4910_via_is_window_resized = true; 4911_via_show_img(_via_image_index); 4912 4913if (_via_is_canvas_zoomed) { 4914reset_zoom_level(); 4915} 4916} 4917break; 4918} 4919} 4920 4921// 4922// Shortcut key handlers 4923// 4924function _via_window_keydown_handler(e) { 4925if ( e.target === document.body ) { 4926// process the keyboard event 4927_via_handle_global_keydown_event(e); 4928} 4929} 4930 4931// global keys are active irrespective of element focus 4932// arrow keys, n, p, s, o, space, d, Home, End, PageUp, PageDown 4933function _via_handle_global_keydown_event(e) { 4934// zoom 4935if (_via_current_image_loaded) { 4936if ( e.key === "+") { 4937zoom_in(); 4938return; 4939} 4940 4941if ( e.key === "=") { 4942reset_zoom_level(); 4943return; 4944} 4945 4946if ( e.key === "-") { 4947zoom_out(); 4948return; 4949} 4950} 4951 4952if ( e.key === 'ArrowRight' || e.key === 'n') { 4953move_to_next_image(); 4954e.preventDefault(); 4955return; 4956} 4957if ( e.key === 'ArrowLeft' || e.key === 'p') { 4958move_to_prev_image(); 4959e.preventDefault(); 4960return; 4961} 4962 4963if ( e.key === 'ArrowUp' ) { 4964region_visualisation_update('region_label', '__via_region_id__', 1); 4965e.preventDefault(); 4966return; 4967} 4968 4969if ( e.key === 'ArrowDown' ) { 4970region_visualisation_update('region_color', '__via_default_region_color__', -1); 4971e.preventDefault(); 4972return; 4973} 4974 4975 4976if ( e.key === 'Home') { 4977show_first_image(); 4978e.preventDefault(); 4979return; 4980} 4981if ( e.key === 'End') { 4982show_last_image(); 4983e.preventDefault(); 4984return; 4985} 4986if ( e.key === 'PageDown') { 4987jump_to_next_image_block(); 4988e.preventDefault(); 4989return; 4990} 4991if ( e.key === 'PageUp') { 4992jump_to_prev_image_block(); 4993e.preventDefault(); 4994return; 4995} 4996 4997if ( e.key === 'a' ) { 4998if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 4999// select all in image grid 5000image_grid_group_toggle_select_all(); 5001} 5002} 5003 5004if ( e.key === 'Escape' ) { 5005e.preventDefault(); 5006if ( _via_is_loading_current_image ) { 5007_via_cancel_current_image_loading(); 5008} 5009 5010if ( _via_is_user_resizing_region ) { 5011// cancel region resizing action 5012_via_is_user_resizing_region = false; 5013} 5014 5015if ( _via_is_region_selected ) { 5016// clear all region selections 5017_via_is_region_selected = false; 5018_via_user_sel_region_id = -1; 5019toggle_all_regions_selection(false); 5020} 5021 5022if ( _via_is_user_drawing_polygon ) { 5023_via_is_user_drawing_polygon = false; 5024_via_canvas_regions.splice(_via_current_polygon_region_id, 1); 5025} 5026 5027if ( _via_is_user_drawing_region ) { 5028_via_is_user_drawing_region = false; 5029} 5030 5031if ( _via_is_user_resizing_region ) { 5032_via_is_user_resizing_region = false 5033} 5034 5035if ( _via_is_user_moving_region ) { 5036_via_is_user_moving_region = false 5037} 5038 5039_via_redraw_reg_canvas(); 5040return; 5041} 5042 5043if ( e.key === ' ' ) { // Space key 5044if ( e.ctrlKey ) { 5045annotation_editor_toggle_on_image_editor(); 5046} else { 5047annotation_editor_toggle_all_regions_editor(); 5048} 5049e.preventDefault(); 5050return; 5051} 5052 5053if ( e.key === 'F1' ) { // F1 for help 5054set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_GETTING_STARTED); 5055e.preventDefault(); 5056return; 5057} 5058if ( e.key === 'F2' ) { // F2 for about 5059set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_ABOUT); 5060e.preventDefault(); 5061return; 5062} 5063} 5064 5065function _via_reg_canvas_keyup_handler(e) { 5066if ( e.key === 'Control' ) { 5067_via_is_ctrl_pressed = false; 5068} 5069} 5070 5071function _via_reg_canvas_keydown_handler(e) { 5072if ( e.key === 'Control' ) { 5073_via_is_ctrl_pressed = true; 5074} 5075 5076if (_via_current_image_loaded) { 5077if ( e.key === 'Enter' ) { 5078if ( _via_current_shape === VIA_REGION_SHAPE.POLYLINE || 5079_via_current_shape === VIA_REGION_SHAPE.POLYGON) { 5080_via_polyshape_finish_drawing(); 5081} 5082} 5083if ( e.key === 'Backspace' ) { 5084if ( _via_current_shape === VIA_REGION_SHAPE.POLYLINE || 5085_via_current_shape === VIA_REGION_SHAPE.POLYGON) { 5086_via_polyshape_delete_last_vertex(); 5087} 5088} 5089 5090if ( e.key === 'a' ) { 5091sel_all_regions(); 5092e.preventDefault(); 5093return; 5094} 5095 5096if ( e.key === 'c' ) { 5097if (_via_is_region_selected || 5098_via_is_all_region_selected) { 5099copy_sel_regions(); 5100} 5101e.preventDefault(); 5102return; 5103} 5104 5105if ( e.key === 'v' ) { 5106paste_sel_regions_in_current_image(); 5107e.preventDefault(); 5108return; 5109} 5110 5111if ( e.key === 'b' ) { 5112toggle_region_boundary_visibility(); 5113e.preventDefault(); 5114return; 5115} 5116 5117if ( e.key === 'l' ) { 5118toggle_region_id_visibility(); 5119e.preventDefault(); 5120return; 5121} 5122 5123if ( e.key === 'd' ) { 5124if ( _via_is_region_selected || 5125_via_is_all_region_selected ) { 5126del_sel_regions(); 5127} 5128e.preventDefault(); 5129return; 5130} 5131 5132if ( _via_is_region_selected ) { 5133if ( e.key === 'ArrowRight' || 5134e.key === 'ArrowLeft' || 5135e.key === 'ArrowDown' || 5136e.key === 'ArrowUp' ) { 5137var del = 1; 5138if ( e.shiftKey ) { 5139del = 10; 5140} 5141var move_x = 0; 5142var move_y = 0; 5143switch( e.key ) { 5144case 'ArrowLeft': 5145move_x = -del; 5146break; 5147case 'ArrowUp': 5148move_y = -del; 5149break; 5150case 'ArrowRight': 5151move_x = del; 5152break; 5153case 'ArrowDown': 5154move_y = del; 5155break; 5156} 5157_via_move_selected_regions(move_x, move_y); 5158_via_redraw_reg_canvas(); 5159e.preventDefault(); 5160return; 5161} 5162} 5163} 5164_via_handle_global_keydown_event(e); 5165} 5166 5167function _via_polyshape_finish_drawing() { 5168if ( _via_is_user_drawing_polygon ) { 5169// double click is used to indicate completion of 5170// polygon or polyline drawing action 5171var new_region_id = _via_current_polygon_region_id; 5172var new_region_shape = _via_current_shape; 5173 5174var npts = _via_canvas_regions[new_region_id].shape_attributes['all_points_x'].length; 5175if ( npts <=2 && new_region_shape === VIA_REGION_SHAPE.POLYGON ) { 5176show_message('For a polygon, you must define at least 3 points. ' + 5177'Press [Esc] to cancel drawing operation.!'); 5178return; 5179} 5180if ( npts <=1 && new_region_shape === VIA_REGION_SHAPE.POLYLINE ) { 5181show_message('A polyline must have at least 2 points. ' + 5182'Press [Esc] to cancel drawing operation.!'); 5183return; 5184} 5185 5186var img_id = _via_image_id; 5187_via_current_polygon_region_id = -1; 5188_via_is_user_drawing_polygon = false; 5189_via_is_user_drawing_region = false; 5190 5191_via_img_metadata[img_id].regions[new_region_id] = {}; // create placeholder 5192_via_polyshape_add_new_polyshape(img_id, new_region_shape, new_region_id); 5193select_only_region(new_region_id); // select new region 5194set_region_annotations_to_default_value( new_region_id ); 5195annotation_editor_add_row( new_region_id ); 5196annotation_editor_scroll_to_row( new_region_id ); 5197 5198_via_redraw_reg_canvas(); 5199_via_reg_canvas.focus(); 5200} 5201return; 5202} 5203 5204function _via_polyshape_delete_last_vertex() { 5205if ( _via_is_user_drawing_polygon ) { 5206var npts = _via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_x'].length; 5207if ( npts > 0 ) { 5208_via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_x'].splice(npts - 1, 1); 5209_via_canvas_regions[_via_current_polygon_region_id].shape_attributes['all_points_y'].splice(npts - 1, 1); 5210 5211_via_redraw_reg_canvas(); 5212_via_reg_canvas.focus(); 5213} 5214} 5215} 5216 5217function _via_polyshape_add_new_polyshape(img_id, region_shape, region_id) { 5218// add all polygon points stored in _via_canvas_regions[] 5219var all_points_x = _via_canvas_regions[region_id].shape_attributes['all_points_x'].slice(0); 5220var all_points_y = _via_canvas_regions[region_id].shape_attributes['all_points_y'].slice(0); 5221 5222var canvas_all_points_x = []; 5223var canvas_all_points_y = []; 5224var n = all_points_x.length; 5225var i; 5226for ( i = 0; i < n; ++i ) { 5227all_points_x[i] = Math.round( all_points_x[i] * _via_canvas_scale ); 5228all_points_y[i] = Math.round( all_points_y[i] * _via_canvas_scale ); 5229 5230canvas_all_points_x[i] = Math.round( all_points_x[i] / _via_canvas_scale ); 5231canvas_all_points_y[i] = Math.round( all_points_y[i] / _via_canvas_scale ); 5232} 5233 5234var polygon_region = new file_region(); 5235polygon_region.shape_attributes['name'] = region_shape; 5236polygon_region.shape_attributes['all_points_x'] = all_points_x; 5237polygon_region.shape_attributes['all_points_y'] = all_points_y; 5238_via_img_metadata[img_id].regions[region_id] = polygon_region; 5239 5240// update canvas 5241if ( img_id === _via_image_id ) { 5242_via_canvas_regions[region_id].shape_attributes['name'] = region_shape; 5243_via_canvas_regions[region_id].shape_attributes['all_points_x'] = canvas_all_points_x; 5244_via_canvas_regions[region_id].shape_attributes['all_points_y'] = canvas_all_points_y; 5245} 5246} 5247 5248function del_sel_regions() { 5249if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5250return; 5251} 5252 5253if ( !_via_current_image_loaded ) { 5254show_message('First load some images!'); 5255return; 5256} 5257 5258var del_region_count = 0; 5259if ( _via_is_all_region_selected ) { 5260del_region_count = _via_canvas_regions.length; 5261_via_canvas_regions.splice(0); 5262_via_img_metadata[_via_image_id].regions.splice(0); 5263} else { 5264var sorted_sel_reg_id = []; 5265for ( var i = 0; i < _via_canvas_regions.length; ++i ) { 5266if ( _via_region_selected_flag[i] ) { 5267sorted_sel_reg_id.push(i); 5268_via_region_selected_flag[i] = false; 5269} 5270} 5271sorted_sel_reg_id.sort( function(a,b) { 5272return (b-a); 5273}); 5274for ( var i = 0; i < sorted_sel_reg_id.length; ++i ) { 5275_via_canvas_regions.splice( sorted_sel_reg_id[i], 1); 5276_via_img_metadata[_via_image_id].regions.splice( sorted_sel_reg_id[i], 1); 5277del_region_count += 1; 5278} 5279 5280if ( sorted_sel_reg_id.length ) { 5281_via_reg_canvas.style.cursor = "default"; 5282} 5283} 5284 5285_via_is_all_region_selected = false; 5286_via_is_region_selected = false; 5287_via_user_sel_region_id = -1; 5288 5289if ( _via_canvas_regions.length === 0 ) { 5290// all regions were deleted, hence clear region canvas 5291_via_clear_reg_canvas(); 5292} else { 5293_via_redraw_reg_canvas(); 5294} 5295_via_reg_canvas.focus(); 5296annotation_editor_show(); 5297 5298show_message('Deleted ' + del_region_count + ' selected regions'); 5299} 5300 5301function sel_all_regions() { 5302if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5303image_grid_group_toggle_select_all(); 5304return; 5305} 5306 5307if (!_via_current_image_loaded) { 5308show_message('First load some images!'); 5309return; 5310} 5311 5312toggle_all_regions_selection(true); 5313_via_is_all_region_selected = true; 5314_via_redraw_reg_canvas(); 5315} 5316 5317function copy_sel_regions() { 5318if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5319return; 5320} 5321 5322if (!_via_current_image_loaded) { 5323show_message('First load some images!'); 5324return; 5325} 5326 5327if (_via_is_region_selected || 5328_via_is_all_region_selected) { 5329_via_copied_image_regions.splice(0); 5330for ( var i = 0; i < _via_img_metadata[_via_image_id].regions.length; ++i ) { 5331var img_region = _via_img_metadata[_via_image_id].regions[i]; 5332var canvas_region = _via_canvas_regions[i]; 5333if ( _via_region_selected_flag[i] ) { 5334_via_copied_image_regions.push( clone_image_region(img_region) ); 5335} 5336} 5337show_message('Copied ' + _via_copied_image_regions.length + 5338' selected regions. Press Ctrl + v to paste'); 5339} else { 5340show_message('Select a region first!'); 5341} 5342} 5343 5344function paste_sel_regions_in_current_image() { 5345if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5346return; 5347} 5348 5349if ( !_via_current_image_loaded ) { 5350show_message('First load some images!'); 5351return; 5352} 5353 5354if ( _via_copied_image_regions.length ) { 5355var pasted_reg_count = 0; 5356for ( var i = 0; i < _via_copied_image_regions.length; ++i ) { 5357// ensure copied the regions are within this image's boundaries 5358var bbox = get_region_bounding_box( _via_copied_image_regions[i] ); 5359if (bbox[2] < _via_current_image_width && 5360bbox[3] < _via_current_image_height) { 5361var r = clone_image_region(_via_copied_image_regions[i]); 5362_via_img_metadata[_via_image_id].regions.push(r); 5363 5364pasted_reg_count += 1; 5365} 5366} 5367_via_load_canvas_regions(); 5368var discarded_reg_count = _via_copied_image_regions.length - pasted_reg_count; 5369show_message('Pasted ' + pasted_reg_count + ' regions. ' + 5370'Discarded ' + discarded_reg_count + ' regions exceeding image boundary.'); 5371_via_redraw_reg_canvas(); 5372_via_reg_canvas.focus(); 5373} else { 5374show_message('To paste a region, you first need to select a region and copy it!'); 5375} 5376} 5377 5378function paste_to_multiple_images_with_confirm() { 5379if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5380return; 5381} 5382 5383if ( _via_copied_image_regions.length === 0 ) { 5384show_message('First copy some regions!'); 5385return; 5386} 5387 5388var config = {'title':'Paste Regions to Multiple Images' }; 5389var input = { 'region_count': { type:'text', name:'Number of copied regions', value:_via_copied_image_regions.length, disabled:true }, 5390'prev_next_count':{ type:'text', name:'Copy to (count format)<br><span style="font-size:0.8rem">For example: to paste copied regions to the <i>previous 2 images</i> and <i>next 3 images</i>, type <strong>2,3</strong> in the textbox and to paste only in <i>next 5 images</i>, type <strong>0,5</strong></span>', placeholder:'2,3', disabled:false, size:30}, 5391'img_index_list':{ type:'text', name:'Copy to (image index list)<br><span style="font-size:0.8rem">For example: <strong>2-5,7,9</strong> pastes the copied regions to the images with the following id <i>2,3,4,5,7,9</i> and <strong>3,8,141</strong> pastes to the images with id <i>3,8 and 141</i></span>', placeholder:'2-5,7,9', disabled:false, size:30}, 5392'regex':{ type:'text', name:'Copy to filenames matching a regular expression<br><span style="font-size:0.8rem">For example: <strong>_large</strong> pastes the copied regions to all images whose filename contain the keyword <i>_large</i></span>', placeholder:'regular expression', disabled:false, size:30}, 5393'include_region_attributes':{ type:'checkbox', name:'Paste also the region annotations', checked:true}, 5394}; 5395 5396invoke_with_user_inputs(paste_to_multiple_images_confirmed, input, config); 5397} 5398 5399function paste_to_multiple_images_confirmed(input) { 5400// keep a copy of user inputs for the undo operation 5401_via_paste_to_multiple_images_input = input; 5402var intersect = generate_img_index_list(input); 5403var i; 5404var total_pasted_region_count = 0; 5405for ( i = 0; i < intersect.length; i++ ) { 5406total_pasted_region_count += paste_regions( intersect[i] ); 5407} 5408 5409show_message('Pasted [' + total_pasted_region_count + '] regions ' + 5410'in ' + intersect.length + ' images'); 5411 5412if ( intersect.includes(_via_image_index) ) { 5413_via_load_canvas_regions(); 5414_via_redraw_reg_canvas(); 5415_via_reg_canvas.focus(); 5416} 5417user_input_default_cancel_handler(); 5418} 5419 5420function paste_regions(img_index) { 5421var pasted_reg_count = 0; 5422if ( _via_copied_image_regions.length ) { 5423var img_id = _via_image_id_list[img_index]; 5424var i; 5425for ( i = 0; i < _via_copied_image_regions.length; ++i ) { 5426var r = clone_image_region(_via_copied_image_regions[i]); 5427_via_img_metadata[img_id].regions.push(r); 5428 5429pasted_reg_count += 1; 5430} 5431} 5432return pasted_reg_count; 5433} 5434 5435 5436function del_sel_regions_with_confirm() { 5437if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5438return; 5439} 5440 5441if ( _via_copied_image_regions.length === 0 ) { 5442show_message('First copy some regions!'); 5443return; 5444} 5445 5446var prev_next_count, img_index_list, regex; 5447if ( _via_paste_to_multiple_images_input ) { 5448prev_next_count = _via_paste_to_multiple_images_input.prev_next_count.value; 5449img_index_list = _via_paste_to_multiple_images_input.img_index_list.value; 5450regex = _via_paste_to_multiple_images_input.regex.value; 5451} 5452 5453var config = {'title':'Undo Regions Pasted to Multiple Images' }; 5454var input = { 'region_count': { type:'text', name:'Number of regions selected', value:_via_copied_image_regions.length, disabled:true }, 5455'prev_next_count':{ type:'text', name:'Delete from (count format)<br><span style="font-size:0.8rem">For example: to delete copied regions from the <i>previous 2 images</i> and <i>next 3 images</i>, type <strong>2,3</strong> in the textbox and to delete regions only in <i>next 5 images</i>, type <strong>0,5</strong></span>', placeholder:'2,3', disabled:false, size:30, value:prev_next_count}, 5456'img_index_list':{ type:'text', name:'Delete from (image index list)<br><span style="font-size:0.8rem">For example: <strong>2-5,7,9</strong> deletes the copied regions to the images with the following id <i>2,3,4,5,7,9</i> and <strong>3,8,141</strong> deletes regions from the images with id <i>3,8 and 141</i></span>', placeholder:'2-5,7,9', disabled:false, size:30, value:img_index_list}, 5457'regex':{ type:'text', name:'Delete from filenames matching a regular expression<br><span style="font-size:0.8rem">For example: <strong>_large</strong> deletes the copied regions from all images whose filename contain the keyword <i>_large</i></span>', placeholder:'regular expression', disabled:false, size:30, value:regex}, 5458}; 5459 5460invoke_with_user_inputs(del_sel_regions_confirmed, input, config); 5461} 5462 5463function del_sel_regions_confirmed(input) { 5464user_input_default_cancel_handler(); 5465var intersect = generate_img_index_list(input); 5466var i; 5467var total_deleted_region_count = 0; 5468for ( i = 0; i < intersect.length; i++ ) { 5469total_deleted_region_count += delete_regions( intersect[i] ); 5470} 5471 5472show_message('Deleted [' + total_deleted_region_count + '] regions ' + 5473'in ' + intersect.length + ' images'); 5474 5475if ( intersect.includes(_via_image_index) ) { 5476_via_load_canvas_regions(); 5477_via_redraw_reg_canvas(); 5478_via_reg_canvas.focus(); 5479} 5480} 5481 5482function delete_regions(img_index) { 5483var del_region_count = 0; 5484if ( _via_copied_image_regions.length ) { 5485var img_id = _via_image_id_list[img_index]; 5486var i; 5487for ( i = 0; i < _via_copied_image_regions.length; ++i ) { 5488var copied_region_shape_str = JSON.stringify(_via_copied_image_regions[i].shape_attributes); 5489var j; 5490// start from last region in order to delete the last pasted region 5491for ( j = _via_img_metadata[img_id].regions.length-1; j >= 0; --j ) { 5492if ( JSON.stringify(_via_img_metadata[img_id].regions[j].shape_attributes) === copied_region_shape_str ) { 5493_via_img_metadata[img_id].regions.splice( j, 1); 5494del_region_count += 1; 5495break; // delete only one matching region 5496} 5497} 5498} 5499} 5500return del_region_count; 5501} 5502 5503function show_first_image() { 5504if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5505if ( _via_image_grid_group_var.length ) { 5506image_grid_group_prev( { 'value':0 } ); // simulate button click 5507} else { 5508show_message('First, create groups by selecting items from "Group by" dropdown list'); 5509} 5510return; 5511} 5512 5513if (_via_img_count > 0) { 5514_via_show_img( _via_img_fn_list_img_index_list[0] ); 5515} 5516} 5517 5518function show_last_image() { 5519if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5520if ( _via_image_grid_group_var.length ) { 5521image_grid_group_prev( { 'value':_via_image_grid_group_var.length-1 } ); // simulate button click 5522} else { 5523show_message('First, create groups by selecting items from "Group by" dropdown list'); 5524} 5525return; 5526} 5527 5528if (_via_img_count > 0) { 5529var last_img_index = _via_img_fn_list_img_index_list.length - 1; 5530_via_show_img( _via_img_fn_list_img_index_list[ last_img_index ] ); 5531} 5532} 5533 5534function jump_image_block_get_count() { 5535var n = _via_img_fn_list_img_index_list.length; 5536if ( n < 20 ) { 5537return 2; 5538} 5539if ( n < 100 ) { 5540return 10; 5541} 5542if ( n < 1000 ) { 5543return 25; 5544} 5545if ( n < 5000 ) { 5546return 50; 5547} 5548if ( n < 10000 ) { 5549return 100; 5550} 5551if ( n < 50000 ) { 5552return 500; 5553} 5554 5555return Math.round( n / 50 ); 5556} 5557 5558function jump_to_next_image_block() { 5559if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5560return; 5561} 5562 5563var jump_count = jump_image_block_get_count(); 5564if ( jump_count > 1 ) { 5565var current_img_index = _via_image_index; 5566if ( _via_img_fn_list_img_index_list.includes( current_img_index ) ) { 5567var list_index = _via_img_fn_list_img_index_list.indexOf( current_img_index ); 5568var next_list_index = list_index + jump_count; 5569if ( (next_list_index + 1) > _via_img_fn_list_img_index_list.length ) { 5570next_list_index = 0; 5571} 5572var next_img_index = _via_img_fn_list_img_index_list[next_list_index]; 5573_via_show_img(next_img_index); 5574} 5575} else { 5576move_to_next_image(); 5577} 5578} 5579 5580function jump_to_prev_image_block() { 5581if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5582return; 5583} 5584 5585var jump_count = jump_image_block_get_count(); 5586if ( jump_count > 1 ) { 5587var current_img_index = _via_image_index; 5588if ( _via_img_fn_list_img_index_list.includes( current_img_index ) ) { 5589var list_index = _via_img_fn_list_img_index_list.indexOf( current_img_index ); 5590var prev_list_index = list_index - jump_count; 5591if ( prev_list_index < 0 ) { 5592prev_list_index = _via_img_fn_list_img_index_list.length - 1; 5593} 5594var prev_img_index = _via_img_fn_list_img_index_list[prev_list_index]; 5595_via_show_img(prev_img_index); 5596} 5597} else { 5598move_to_prev_image(); 5599} 5600} 5601 5602function move_to_prev_image() { 5603if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5604if ( _via_image_grid_group_var.length ) { 5605var last_group_index = _via_image_grid_group_var.length - 1; 5606image_grid_group_prev( { 'value':last_group_index } ); // simulate button click 5607} else { 5608show_message('First, create groups by selecting items from "Group by" dropdown list'); 5609} 5610return; 5611} 5612 5613if (_via_img_count > 0) { 5614var current_img_index = _via_image_index; 5615if ( _via_img_fn_list_img_index_list.includes( current_img_index ) ) { 5616var list_index = _via_img_fn_list_img_index_list.indexOf( current_img_index ); 5617var next_list_index = list_index - 1; 5618if ( next_list_index === -1 ) { 5619next_list_index = _via_img_fn_list_img_index_list.length - 1; 5620} 5621var next_img_index = _via_img_fn_list_img_index_list[next_list_index]; 5622_via_show_img(next_img_index); 5623} else { 5624if ( _via_img_fn_list_img_index_list.length === 0 ) { 5625show_message('Filtered file list does not any files!'); 5626} else { 5627_via_show_img( _via_img_fn_list_img_index_list[0] ); 5628} 5629} 5630 5631if (typeof _via_hook_prev_image === 'function') { 5632_via_hook_prev_image(current_img_index); 5633} 5634} 5635} 5636 5637function move_to_next_image() { 5638if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5639if ( _via_image_grid_group_var.length ) { 5640var last_group_index = _via_image_grid_group_var.length - 1; 5641image_grid_group_next( { 'value':last_group_index } ); // simulate button click 5642} else { 5643show_message('First, create groups by selecting items from "Group by" dropdown list'); 5644} 5645return; 5646} 5647 5648if (_via_img_count > 0) { 5649var current_img_index = _via_image_index; 5650if ( _via_img_fn_list_img_index_list.includes( current_img_index ) ) { 5651var list_index = _via_img_fn_list_img_index_list.indexOf( current_img_index ); 5652var next_list_index = list_index + 1; 5653if ( next_list_index === _via_img_fn_list_img_index_list.length ) { 5654next_list_index = 0; 5655} 5656var next_img_index = _via_img_fn_list_img_index_list[next_list_index]; 5657_via_show_img(next_img_index); 5658} else { 5659if ( _via_img_fn_list_img_index_list.length === 0 ) { 5660show_message('Filtered file list does not contain any files!'); 5661} else { 5662_via_show_img( _via_img_fn_list_img_index_list[0] ); 5663} 5664} 5665 5666if (typeof _via_hook_next_image === 'function') { 5667_via_hook_next_image(current_img_index); 5668} 5669} 5670} 5671 5672function set_zoom(zoom_level_index) { 5673if ( zoom_level_index === VIA_CANVAS_DEFAULT_ZOOM_LEVEL_INDEX ) { 5674_via_is_canvas_zoomed = false; 5675_via_canvas_zoom_level_index = VIA_CANVAS_DEFAULT_ZOOM_LEVEL_INDEX; 5676} else { 5677_via_is_canvas_zoomed = true; 5678_via_canvas_zoom_level_index = zoom_level_index; 5679} 5680 5681var zoom_scale = VIA_CANVAS_ZOOM_LEVELS[_via_canvas_zoom_level_index]; 5682set_all_canvas_scale(zoom_scale); 5683var canvas_w = ( _via_current_image.naturalWidth * zoom_scale ) / _via_canvas_scale_without_zoom; 5684var canvas_h = ( _via_current_image.naturalHeight * zoom_scale ) / _via_canvas_scale_without_zoom; 5685set_all_canvas_size(canvas_w, canvas_h); 5686_via_canvas_scale = _via_canvas_scale_without_zoom / zoom_scale; 5687_via_canvas_scale = _via_canvas_scale_without_zoom / zoom_scale; 5688 5689if ( zoom_scale === 1 ) { 5690VIA_REGION_POINT_RADIUS = VIA_REGION_POINT_RADIUS_DEFAULT; 5691} else { 5692if ( zoom_scale > 1 ) { 5693VIA_REGION_POINT_RADIUS = VIA_REGION_POINT_RADIUS_DEFAULT * zoom_scale; 5694} 5695} 5696 5697_via_load_canvas_regions(); // image to canvas space transform 5698_via_redraw_reg_canvas(); 5699_via_reg_canvas.focus(); 5700update_vertical_space(); 5701} 5702 5703function reset_zoom_level() { 5704if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5705image_grid_image_size_reset(); 5706show_message('Zoom reset'); 5707return; 5708} 5709 5710if (!_via_current_image_loaded) { 5711show_message('First load some images!'); 5712return; 5713} 5714 5715if (_via_is_canvas_zoomed) { 5716set_zoom(VIA_CANVAS_DEFAULT_ZOOM_LEVEL_INDEX); 5717show_message('Zoom reset'); 5718} else { 5719show_message('Cannot reset zoom because image zoom has not been applied!'); 5720} 5721update_vertical_space(); 5722} 5723 5724function zoom_in() { 5725if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5726image_grid_image_size_increase(); 5727show_message('Increased size of images shown in image grid'); 5728return; 5729} 5730 5731if (!_via_current_image_loaded) { 5732show_message('First load some images!'); 5733return; 5734} 5735 5736if ( _via_is_user_drawing_polygon || _via_is_user_drawing_region ) { 5737return; 5738} 5739 5740if (_via_canvas_zoom_level_index === (VIA_CANVAS_ZOOM_LEVELS.length-1)) { 5741show_message('Further zoom-in not possible'); 5742} else { 5743var new_zoom_level_index = _via_canvas_zoom_level_index + 1; 5744set_zoom( new_zoom_level_index ); 5745show_message('Zoomed in to level ' + VIA_CANVAS_ZOOM_LEVELS[_via_canvas_zoom_level_index] + 'X'); 5746} 5747} 5748 5749function zoom_out() { 5750if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5751image_grid_image_size_decrease(); 5752show_message('Reduced size of images shown in image grid'); 5753return; 5754} 5755 5756if (!_via_current_image_loaded) { 5757show_message('First load some images!'); 5758return; 5759} 5760 5761if ( _via_is_user_drawing_polygon || _via_is_user_drawing_region ) { 5762return; 5763} 5764 5765if (_via_canvas_zoom_level_index === 0) { 5766show_message('Further zoom-out not possible'); 5767} else { 5768var new_zoom_level_index = _via_canvas_zoom_level_index - 1; 5769set_zoom( new_zoom_level_index ); 5770show_message('Zoomed out to level ' + VIA_CANVAS_ZOOM_LEVELS[_via_canvas_zoom_level_index] + 'X'); 5771} 5772} 5773 5774function toggle_region_boundary_visibility() { 5775if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE ) { 5776_via_is_region_boundary_visible = !_via_is_region_boundary_visible; 5777_via_redraw_reg_canvas(); 5778_via_reg_canvas.focus(); 5779} 5780 5781if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 5782if ( _via_settings.ui.image_grid.show_region_shape ) { 5783_via_settings.ui.image_grid.show_region_shape = false; 5784document.getElementById('image_grid_content_rshape').innerHTML = ''; 5785} else { 5786_via_settings.ui.image_grid.show_region_shape = true; 5787image_grid_page_show_all_regions(); 5788} 5789} 5790} 5791 5792function toggle_region_id_visibility() { 5793_via_is_region_id_visible = !_via_is_region_id_visible; 5794_via_redraw_reg_canvas(); 5795_via_reg_canvas.focus(); 5796} 5797 5798function toggle_region_info_visibility() { 5799var elem = document.getElementById('region_info'); 5800// toggle between displaying and not displaying 5801if ( elem.classList.contains('display_none') ) { 5802elem.classList.remove('display_none'); 5803_via_is_region_info_visible = true; 5804} else { 5805elem.classList.add('display_none'); 5806_via_is_region_info_visible = false; 5807} 5808} 5809 5810// 5811// Mouse wheel event listener 5812// 5813function _via_reg_canvas_mouse_wheel_listener(e) { 5814if (!_via_current_image_loaded) { 5815return; 5816} 5817 5818if ( e.ctrlKey ) { 5819// perform zoom 5820if (e.deltaY < 0) { 5821zoom_in(); 5822} else { 5823zoom_out(); 5824} 5825e.preventDefault(); 5826} 5827} 5828 5829function region_visualisation_update(type, default_id, next_offset) { 5830var attr_list = [ default_id ]; 5831attr_list = attr_list.concat(Object.keys(_via_attributes['region'])); 5832var n = attr_list.length; 5833var current_index = attr_list.indexOf(_via_settings.ui.image[type]); 5834var new_index; 5835if ( current_index !== -1 ) { 5836new_index = current_index + next_offset; 5837 5838if ( new_index < 0 ) { 5839new_index = n + new_index; 5840} 5841if ( new_index >= n ) { 5842new_index = new_index - n; 5843} 5844switch(type) { 5845case 'region_label': 5846_via_settings.ui.image.region_label = attr_list[new_index]; 5847_via_redraw_reg_canvas(); 5848break; 5849case 'region_color': 5850_via_settings.ui.image.region_color = attr_list[new_index]; 5851_via_regions_group_color_init(); 5852_via_redraw_reg_canvas(); 5853} 5854 5855var type_str = type.replace('_', ' '); 5856if ( _via_settings.ui.image[type].startsWith('__via') ) { 5857show_message(type_str + ' cleared'); 5858} else { 5859show_message(type_str + ' set to region attribute [' + _via_settings.ui.image[type] + ']'); 5860} 5861} 5862} 5863 5864// 5865// left sidebar toolbox maintainer 5866// 5867function leftsidebar_toggle() { 5868var leftsidebar = document.getElementById('leftsidebar'); 5869if ( leftsidebar.style.display === 'none' ) { 5870leftsidebar.style.display = 'table-cell'; 5871document.getElementById('leftsidebar_collapse_panel').style.display = 'none'; 5872} else { 5873leftsidebar.style.display = 'none'; 5874document.getElementById('leftsidebar_collapse_panel').style.display = 'table-cell'; 5875} 5876_via_update_ui_components(); 5877} 5878 5879function leftsidebar_increase_width() { 5880var leftsidebar = document.getElementById('leftsidebar'); 5881var new_width = _via_settings.ui.leftsidebar_width + VIA_LEFTSIDEBAR_WIDTH_CHANGE; 5882leftsidebar.style.width = new_width + 'rem'; 5883_via_settings.ui.leftsidebar_width = new_width; 5884if ( _via_current_image_loaded ) { 5885_via_show_img(_via_image_index); 5886} 5887} 5888 5889function leftsidebar_decrease_width() { 5890var leftsidebar = document.getElementById('leftsidebar'); 5891var new_width = _via_settings.ui.leftsidebar_width - VIA_LEFTSIDEBAR_WIDTH_CHANGE; 5892if ( new_width >= 5 ) { 5893leftsidebar.style.width = new_width + 'rem'; 5894_via_settings.ui.leftsidebar_width = new_width; 5895if ( _via_current_image_loaded ) { 5896_via_show_img(_via_image_index); 5897} 5898} 5899} 5900 5901function leftsidebar_show() { 5902var leftsidebar = document.getElementById('leftsidebar'); 5903leftsidebar.style.display = 'table-cell'; 5904document.getElementById('leftsidebar_collapse_panel').style.display = 'none'; 5905} 5906 5907// source: https://www.w3schools.com/howto/howto_js_accordion.asp 5908function init_leftsidebar_accordion() { 5909var leftsidebar = document.getElementById('leftsidebar'); 5910leftsidebar.style.width = _via_settings.ui.leftsidebar_width + 'rem'; 5911 5912var acc = document.getElementsByClassName('leftsidebar_accordion'); 5913var i; 5914for ( i = 0; i < acc.length; ++i ) { 5915acc[i].addEventListener('click', function() { 5916update_vertical_space(); 5917this.classList.toggle('active'); 5918this.nextElementSibling.classList.toggle('show'); 5919 5920switch( this.innerHTML ) { 5921case 'Attributes': 5922update_attributes_update_panel(); 5923break; 5924case 'Project': 5925update_img_fn_list(); 5926break; 5927} 5928}); 5929} 5930} 5931 5932// 5933// image filename list shown in leftsidebar panel 5934// 5935function is_img_fn_list_visible() { 5936return img_fn_list_panel.classList.contains('show'); 5937} 5938 5939function img_loading_spinbar(image_index, show) { 5940var panel = document.getElementById('project_panel_title'); 5941if ( show ) { 5942panel.innerHTML = 'Project <span style="margin-left:1rem;" class="loading_spinbox"></span>'; 5943} else { 5944panel.innerHTML = 'Project'; 5945} 5946} 5947 5948function update_img_fn_list() { 5949var regex = document.getElementById('img_fn_list_regex').value; 5950var p = document.getElementById('filelist_preset_filters_list'); 5951if ( regex === '' || regex === null ) { 5952if ( p.selectedIndex === 0 ) { 5953// show all files 5954_via_img_fn_list_html = []; 5955_via_img_fn_list_img_index_list = []; 5956_via_img_fn_list_html.push('<ul>'); 5957for ( var i=0; i < _via_image_filename_list.length; ++i ) { 5958_via_img_fn_list_html.push( img_fn_list_ith_entry_html(i) ); 5959_via_img_fn_list_img_index_list.push(i); 5960} 5961_via_img_fn_list_html.push('</ul>'); 5962img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 5963img_fn_list_scroll_to_current_file(); 5964} else { 5965// filter according to preset filters 5966img_fn_list_onpresetfilter_select(); 5967} 5968} else { 5969if ( p.selectedIndex === 6 ) { 5970// Filter By Region Attribute 5971filter_selected_region_attribute(regex); 5972} else { 5973// RegExp 5974img_fn_list_generate_html(regex); 5975img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 5976img_fn_list_scroll_to_current_file(); 5977} 5978} 5979} 5980 5981function img_fn_list_onregex() { 5982var regex = document.getElementById('img_fn_list_regex').value; 5983var p = document.getElementById('filelist_preset_filters_list'); 5984 5985if ( p.selectedIndex === 6 ) { 5986filter_selected_region_attribute(regex); 5987return; 5988} 5989 5990img_fn_list_generate_html( regex ); 5991img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 5992img_fn_list_scroll_to_current_file(); 5993 5994// select 'regex' in the predefined filter list ( Unless Filter By Attribute is Selected) 5995if ( regex === '' ) { 5996p.selectedIndex = 0; 5997} else { 5998if ( p.options[p.selectedIndex].value != 'files_region_attribute' && 5999p.options[p.selectedIndex].value != 'regex' ) { 6000var i; 6001for ( i=0; i<p.options.length; ++i) { 6002if ( p.options[i].value === 'regex' ) { 6003p.selectedIndex = i; 6004break; 6005} 6006} 6007} 6008} 6009} 6010 6011function img_fn_list_onpresetfilter_select() { 6012var p = document.getElementById('filelist_preset_filters_list'); 6013var filter = p.options[p.selectedIndex].value; 6014switch(filter) { 6015case 'all': 6016document.getElementById('img_fn_list_regex').value = ''; 6017img_fn_list_generate_html(); 6018img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 6019img_fn_list_scroll_to_current_file(); 6020break; 6021case 'regex': 6022img_fn_list_onregex(); 6023document.getElementById('img_fn_list_regex').focus(); 6024break; 6025case 'files_region_attribute': 6026img_fn_list_onregex(); 6027document.getElementById('img_fn_list_regex').focus(); 6028break; 6029default: 6030_via_img_fn_list_html = []; 6031_via_img_fn_list_img_index_list = []; 6032_via_img_fn_list_html.push('<ul>'); 6033var i; 6034for ( i=0; i < _via_image_filename_list.length; ++i ) { 6035var img_id = _via_image_id_list[i]; 6036var add_to_list = false; 6037switch(filter) { 6038case 'files_without_region': 6039if ( _via_img_metadata[img_id].regions.length === 0 ) { 6040add_to_list = true; 6041} 6042break; 6043case 'files_missing_region_annotations': 6044if ( is_region_annotation_missing(img_id) ) { 6045add_to_list = true; 6046} 6047break; 6048case 'files_missing_file_annotations': 6049if ( is_file_annotation_missing(img_id) ) { 6050add_to_list = true; 6051} 6052break; 6053case 'files_error_loading': 6054if ( _via_image_load_error[i] === true ) { 6055add_to_list = true; 6056} 6057} 6058if ( add_to_list ) { 6059_via_img_fn_list_html.push( img_fn_list_ith_entry_html(i) ); 6060_via_img_fn_list_img_index_list.push(i); 6061} 6062} 6063_via_img_fn_list_html.push('</ul>'); 6064img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 6065img_fn_list_scroll_to_current_file(); 6066break; 6067} 6068} 6069 6070function filter_selected_region_attribute(property_entry) { 6071const propArray = property_entry.split("="); 6072if ( propArray.length != 2 || propArray[0] === "" || propArray[1] === "") return; 6073var selected_attribute = propArray[0]; 6074var selected_value = propArray[1]; 6075if ( selected_value === "\"\"") selected_value = ""; 6076 6077_via_img_fn_list_html = []; 6078_via_img_fn_list_img_index_list = []; 6079_via_img_fn_list_html.push('<ul>'); 6080 6081if ( _via_attributes.region.hasOwnProperty(selected_attribute) ) { 6082var i; 6083 6084for ( i=0; i < _via_image_filename_list.length; ++i ) { 6085var img_id = _via_image_id_list[i]; 6086var add_to_list = false; 6087var idx; 6088 6089for ( idx = 0; idx < _via_img_metadata[img_id].regions.length; ++idx ) { 6090if ( _via_img_metadata[img_id].regions[idx].region_attributes.hasOwnProperty(selected_attribute) ) { 6091if ( JSON.stringify(_via_img_metadata[img_id].regions[idx].region_attributes[selected_attribute]) === JSON.stringify(selected_value) ) { 6092add_to_list = true; 6093_via_img_fn_list_html.push( img_fn_list_ith_entry_html(i) ); 6094_via_img_fn_list_img_index_list.push(i); 6095break; 6096} 6097} 6098} 6099} 6100} 6101_via_img_fn_list_html.push('</ul>'); 6102img_fn_list.innerHTML = _via_img_fn_list_html.join(''); 6103img_fn_list_scroll_to_current_file(); 6104} 6105 6106function is_region_annotation_missing(img_id) { 6107var region_attribute; 6108var i; 6109for ( i = 0; i < _via_img_metadata[img_id].regions.length; ++i ) { 6110for ( region_attribute in _via_attributes['region'] ) { 6111if ( _via_img_metadata[img_id].regions[i].region_attributes.hasOwnProperty(region_attribute) ) { 6112if ( _via_img_metadata[img_id].regions[i].region_attributes[region_attribute] === '' ) { 6113return true; 6114} 6115} else { 6116return true; 6117} 6118} 6119} 6120return false; 6121} 6122 6123function is_file_annotation_missing(img_id) { 6124var file_attribute; 6125for ( file_attribute in _via_attributes['file'] ) { 6126if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty(file_attribute) ) { 6127if ( _via_img_metadata[img_id].file_attributes[file_attribute] === '' ) { 6128return true; 6129} 6130} else { 6131return true; 6132} 6133} 6134return false; 6135} 6136 6137function img_fn_list_ith_entry_selected(img_index, is_selected) { 6138if ( is_selected ) { 6139img_fn_list_ith_entry_add_css_class(img_index, 'sel'); 6140} else { 6141img_fn_list_ith_entry_remove_css_class(img_index, 'sel'); 6142} 6143} 6144 6145function img_fn_list_ith_entry_error(img_index, is_error) { 6146if ( is_error ) { 6147img_fn_list_ith_entry_add_css_class(img_index, 'error'); 6148} else { 6149img_fn_list_ith_entry_remove_css_class(img_index, 'error'); 6150} 6151} 6152 6153function img_fn_list_ith_entry_add_css_class(img_index, classname) { 6154var li = document.getElementById('fl' + img_index); 6155if ( li && ! li.classList.contains(classname) ) { 6156li.classList.add(classname); 6157} 6158} 6159 6160function img_fn_list_ith_entry_remove_css_class(img_index, classname) { 6161var li = document.getElementById('fl' + img_index); 6162if ( li && li.classList.contains(classname) ) { 6163li.classList.remove(classname); 6164} 6165} 6166 6167function img_fn_list_clear_all_style() { 6168var cn = document.getElementById('img_fn_list').childNodes[0].childNodes; 6169var i, j; 6170var n = cn.length; 6171var nclass; 6172for ( i = 0; i < n; ++i ) { 6173//cn[i].classList = []; // throws error in Edge browser 6174nclass = cn[i].classList.length; 6175if ( nclass ) { 6176for ( j = 0; j < nclass; ++j ) { 6177cn[i].classList.remove( cn[i].classList.item(j) ); 6178} 6179} 6180} 6181} 6182 6183function img_fn_list_clear_css_classname(classname) { 6184var cn = document.getElementById('img_fn_list').childNodes[0].childNodes; 6185var i; 6186var n = cn.length; 6187for ( i = 0; i < n; ++i ) { 6188if ( cn[i].classList.contains(classname) ) { 6189cn[i].classList.remove(classname); 6190} 6191} 6192} 6193 6194function img_fn_list_ith_entry_html(i) { 6195var htmli = ''; 6196var filename = _via_image_filename_list[i]; 6197if ( is_url(filename) ) { 6198filename = filename.substr(0,4) + '...' + get_filename_from_url(filename); 6199} 6200 6201htmli += '<li id="fl' + i + '"'; 6202if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 6203if ( _via_image_grid_page_img_index_list.includes(i) ) { 6204// highlight images being shown in image grid 6205htmli += ' class="sel"'; 6206} 6207 6208} else { 6209if ( i === _via_image_index ) { 6210// highlight the current entry 6211htmli += ' class="sel"'; 6212} 6213} 6214htmli += ' onclick="jump_to_image(' + (i) + ')" title="' + _via_image_filename_list[i] + '">[' + (i+1) + '] ' + decodeURIComponent(filename) + '</li>'; 6215return htmli; 6216} 6217 6218function img_fn_list_generate_html(regex) { 6219_via_img_fn_list_html = []; 6220_via_img_fn_list_img_index_list = []; 6221_via_img_fn_list_html.push('<ul>'); 6222for ( var i=0; i < _via_image_filename_list.length; ++i ) { 6223var filename = _via_image_filename_list[i]; 6224if ( filename.match(regex) !== null ) { 6225_via_img_fn_list_html.push( img_fn_list_ith_entry_html(i) ); 6226_via_img_fn_list_img_index_list.push(i); 6227} 6228} 6229_via_img_fn_list_html.push('</ul>'); 6230} 6231 6232function img_fn_list_scroll_to_current_file() { 6233img_fn_list_scroll_to_file( _via_image_index ); 6234} 6235 6236function img_fn_list_scroll_to_file(file_index) { 6237if( _via_img_fn_list_img_index_list.includes(file_index) ) { 6238var sel_file = document.getElementById( 'fl' + file_index ); 6239var panel_height = img_fn_list.clientHeight - 20; 6240var window_top = img_fn_list.scrollTop; 6241var window_bottom = img_fn_list.scrollTop + panel_height 6242if ( sel_file.offsetTop > window_top ) { 6243if ( sel_file.offsetTop > window_bottom ) { 6244img_fn_list.scrollTop = sel_file.offsetTop; 6245} 6246} else { 6247img_fn_list.scrollTop = sel_file.offsetTop - panel_height; 6248} 6249} 6250} 6251 6252function toggle_img_fn_list_visibility() { 6253leftsidebar_show(); 6254document.getElementById('img_fn_list_panel').classList.toggle('show'); 6255document.getElementById('project_panel_title').classList.toggle('active'); 6256} 6257 6258function toggle_attributes_editor() { 6259leftsidebar_show(); 6260document.getElementById('attributes_editor_panel').classList.toggle('show'); 6261document.getElementById('attributes_editor_panel_title').classList.toggle('active'); 6262} 6263 6264// this vertical spacer is needed to allow scrollbar to show 6265// items like Keyboard Shortcut hidden under the attributes panel 6266function update_vertical_space() { 6267var panel = document.getElementById('vertical_space'); 6268var aepanel = document.getElementById('annotation_editor_panel'); 6269panel.style.height = (aepanel.offsetHeight + 40) + 'px'; 6270} 6271 6272// 6273// region and file attributes update panel 6274// 6275function attribute_update_panel_set_active_button() { 6276var attribute_type; 6277for ( attribute_type in _via_attributes ) { 6278var bid = 'button_show_' + attribute_type + '_attributes'; 6279document.getElementById(bid).classList.remove('active'); 6280} 6281var bid = 'button_show_' + _via_attribute_being_updated + '_attributes'; 6282document.getElementById(bid).classList.add('active'); 6283} 6284 6285function show_region_attributes_update_panel() { 6286_via_attribute_being_updated = 'region'; 6287var rattr_list = Object.keys(_via_attributes['region']); 6288if ( rattr_list.length ) { 6289_via_current_attribute_id = rattr_list[0]; 6290} else { 6291_via_current_attribute_id = ''; 6292} 6293update_attributes_update_panel(); 6294attribute_update_panel_set_active_button(); 6295 6296} 6297 6298function show_file_attributes_update_panel() { 6299_via_attribute_being_updated = 'file'; 6300var fattr_list = Object.keys(_via_attributes['file']); 6301if ( fattr_list.length ) { 6302_via_current_attribute_id = fattr_list[0]; 6303} else { 6304_via_current_attribute_id = ''; 6305} 6306update_attributes_update_panel(); 6307attribute_update_panel_set_active_button(); 6308} 6309 6310function update_attributes_name_list() { 6311var p = document.getElementById('attributes_name_list'); 6312p.innerHTML = ''; 6313 6314var attr; 6315for ( attr in _via_attributes[_via_attribute_being_updated] ) { 6316var option = document.createElement('option'); 6317option.setAttribute('value', attr) 6318option.innerHTML = attr; 6319if ( attr === _via_current_attribute_id ) { 6320option.setAttribute('selected', 'selected'); 6321} 6322p.appendChild(option); 6323} 6324} 6325 6326function update_attributes_update_panel() { 6327if ( document.getElementById('attributes_editor_panel').classList.contains('show') ) { 6328update_attributes_name_list(); 6329show_attribute_properties(); 6330show_attribute_options(); 6331} 6332} 6333 6334function update_attribute_properties_panel() { 6335if ( document.getElementById('attributes_editor_panel').classList.contains('show') ) { 6336show_attribute_properties(); 6337show_attribute_options(); 6338} 6339} 6340 6341function show_attribute_properties() { 6342var attr_list = document.getElementById('attributes_name_list'); 6343document.getElementById('attribute_properties').innerHTML = ''; 6344 6345if ( attr_list.options.length === 0 ) { 6346return; 6347} 6348 6349if ( typeof(_via_current_attribute_id) === 'undefined' || _via_current_attribute_id === '' ) { 6350_via_current_attribute_id = attr_list.options[0].value; 6351} 6352 6353var attr_id = _via_current_attribute_id; 6354var attr_type = _via_attribute_being_updated; 6355var attr_input_type = _via_attributes[attr_type][attr_id].type; 6356var attr_desc = _via_attributes[attr_type][attr_id].description; 6357 6358attribute_property_add_input_property('Name of attribute (appears in exported annotations)', 6359'Name', 6360attr_id, 6361'attribute_name'); 6362attribute_property_add_input_property('Description of attribute (shown to user during annotation session)', 6363'Desc.', 6364attr_desc, 6365'attribute_description'); 6366 6367if ( attr_input_type === 'text' ) { 6368var attr_default_value = _via_attributes[attr_type][attr_id].default_value; 6369attribute_property_add_input_property('Default value of this attribute', 6370'Def.', 6371attr_default_value, 6372'attribute_default_value'); 6373} 6374 6375// add dropdown for type of attribute 6376var p = document.createElement('div'); 6377p.setAttribute('class', 'property'); 6378var c0 = document.createElement('span'); 6379c0.setAttribute('title', 'Attribute type (e.g. text, checkbox, radio, etc)'); 6380c0.innerHTML = 'Type'; 6381var c1 = document.createElement('span'); 6382var c1b = document.createElement('select'); 6383c1b.setAttribute('onchange', 'attribute_property_on_update(this)'); 6384c1b.setAttribute('id', 'attribute_type'); 6385var type_id; 6386for ( type_id in VIA_ATTRIBUTE_TYPE ) { 6387var type = VIA_ATTRIBUTE_TYPE[type_id]; 6388var option = document.createElement('option'); 6389option.setAttribute('value', type); 6390option.innerHTML = type; 6391if ( attr_input_type == type ) { 6392option.setAttribute('selected', 'selected'); 6393} 6394c1b.appendChild(option); 6395} 6396c1.appendChild(c1b); 6397p.appendChild(c0); 6398p.appendChild(c1); 6399document.getElementById('attribute_properties').appendChild(p); 6400} 6401 6402function show_attribute_options() { 6403var attr_list = document.getElementById('attributes_name_list'); 6404document.getElementById('attribute_options').innerHTML = ''; 6405if ( attr_list.options.length === 0 ) { 6406return; 6407} 6408 6409var attr_id = attr_list.value; 6410var attr_type = _via_attributes[_via_attribute_being_updated][attr_id].type; 6411 6412// populate additional options based on attribute type 6413switch( attr_type ) { 6414case VIA_ATTRIBUTE_TYPE.TEXT: 6415// text does not have any additional properties 6416break; 6417case VIA_ATTRIBUTE_TYPE.IMAGE: 6418var p = document.createElement('div'); 6419p.setAttribute('class', 'property'); 6420p.setAttribute('style', 'text-align:center'); 6421var c0 = document.createElement('span'); 6422c0.setAttribute('style', 'width:25%'); 6423c0.setAttribute('title', 'When selected, this is the value that appears in exported annotations'); 6424c0.innerHTML = 'id'; 6425var c1 = document.createElement('span'); 6426c1.setAttribute('style', 'width:60%'); 6427c1.setAttribute('title', 'URL or base64 (see https://www.base64-image.de/) encoded image data that corresponds to the image shown as an option to the annotator'); 6428c1.innerHTML = 'image url or b64'; 6429var c2 = document.createElement('span'); 6430c2.setAttribute('title', 'The default value of this attribute'); 6431c2.innerHTML = 'def.'; 6432p.appendChild(c0); 6433p.appendChild(c1); 6434p.appendChild(c2); 6435document.getElementById('attribute_options').appendChild(p); 6436 6437var options = _via_attributes[_via_attribute_being_updated][attr_id].options; 6438var option_id; 6439for ( option_id in options ) { 6440var option_desc = options[option_id]; 6441 6442var option_default = _via_attributes[_via_attribute_being_updated][attr_id].default_options[option_id]; 6443attribute_property_add_option(attr_id, option_id, option_desc, option_default, attr_type); 6444} 6445attribute_property_add_new_entry_option(attr_id, attr_type); 6446break; 6447case VIA_ATTRIBUTE_TYPE.CHECKBOX: // handled by next case 6448case VIA_ATTRIBUTE_TYPE.DROPDOWN: // handled by next case 6449case VIA_ATTRIBUTE_TYPE.RADIO: 6450var p = document.createElement('div'); 6451p.setAttribute('class', 'property'); 6452p.setAttribute('style', 'text-align:center'); 6453var c0 = document.createElement('span'); 6454c0.setAttribute('style', 'width:25%'); 6455c0.setAttribute('title', 'When selected, this is the value that appears in exported annotations'); 6456c0.innerHTML = 'id'; 6457var c1 = document.createElement('span'); 6458c1.setAttribute('style', 'width:60%'); 6459c1.setAttribute('title', 'This is the text shown as an option to the annotator'); 6460c1.innerHTML = 'description'; 6461var c2 = document.createElement('span'); 6462c2.setAttribute('title', 'The default value of this attribute'); 6463c2.innerHTML = 'def.'; 6464p.appendChild(c0); 6465p.appendChild(c1); 6466p.appendChild(c2); 6467document.getElementById('attribute_options').appendChild(p); 6468 6469var options = _via_attributes[_via_attribute_being_updated][attr_id].options; 6470var option_id; 6471for ( option_id in options ) { 6472var option_desc = options[option_id]; 6473 6474var option_default = _via_attributes[_via_attribute_being_updated][attr_id].default_options[option_id]; 6475attribute_property_add_option(attr_id, option_id, option_desc, option_default, attr_type); 6476} 6477attribute_property_add_new_entry_option(attr_id, attr_type); 6478break; 6479default: 6480console.log('Attribute type ' + attr_type + ' is unavailable'); 6481} 6482} 6483 6484function attribute_property_add_input_property(title, name, value, id) { 6485var p = document.createElement('div'); 6486p.setAttribute('class', 'property'); 6487var c0 = document.createElement('span'); 6488c0.setAttribute('title', title); 6489c0.innerHTML = name; 6490var c1 = document.createElement('span'); 6491var c1b = document.createElement('input'); 6492c1b.setAttribute('onchange', 'attribute_property_on_update(this)'); 6493if ( typeof(value) !== 'undefined' ) { 6494c1b.setAttribute('value', value); 6495} 6496c1b.setAttribute('id', id); 6497c1.appendChild(c1b); 6498p.appendChild(c0); 6499p.appendChild(c1); 6500 6501document.getElementById('attribute_properties').appendChild(p); 6502} 6503 6504function attribute_property_add_option(attr_id, option_id, option_desc, option_default, attribute_type) { 6505var p = document.createElement('div'); 6506p.setAttribute('class', 'property'); 6507var c0 = document.createElement('span'); 6508var c0b = document.createElement('input'); 6509c0b.setAttribute('type', 'text'); 6510c0b.setAttribute('value', option_id); 6511c0b.setAttribute('title', option_id); 6512c0b.setAttribute('onchange', 'attribute_property_on_option_update(this)'); 6513c0b.setAttribute('id', '_via_attribute_option_id_' + option_id); 6514 6515var c1 = document.createElement('span'); 6516var c1b = document.createElement('input'); 6517c1b.setAttribute('type', 'text'); 6518 6519if ( attribute_type === VIA_ATTRIBUTE_TYPE.IMAGE ) { 6520var option_desc_info = option_desc.length + ' bytes of base64 image data'; 6521c1b.setAttribute('value', option_desc_info); 6522c1b.setAttribute('title', 'To update, copy and paste base64 image data in this text box'); 6523} else { 6524c1b.setAttribute('value', option_desc); 6525c1b.setAttribute('title', option_desc); 6526} 6527c1b.setAttribute('onchange', 'attribute_property_on_option_update(this)'); 6528c1b.setAttribute('id', '_via_attribute_option_description_' + option_id); 6529 6530var c2 = document.createElement('span'); 6531var c2b = document.createElement('input'); 6532c2b.setAttribute('type', attribute_type); 6533if ( typeof option_default !== 'undefined' ) { 6534c2b.checked = option_default; 6535} 6536if ( attribute_type === 'radio' || attribute_type === 'image' || attribute_type === 'dropdown' ) { 6537// ensured that user can activate only one radio button 6538c2b.setAttribute('type', 'radio'); 6539c2b.setAttribute('name', attr_id); 6540} 6541 6542c2b.setAttribute('onchange', 'attribute_property_on_option_update(this)'); 6543c2b.setAttribute('id', '_via_attribute_option_default_' + option_id); 6544 6545c0.appendChild(c0b); 6546c1.appendChild(c1b); 6547c2.appendChild(c2b); 6548p.appendChild(c0); 6549p.appendChild(c1); 6550p.appendChild(c2); 6551 6552document.getElementById('attribute_options').appendChild(p); 6553} 6554 6555function attribute_property_add_new_entry_option(attr_id, attribute_type) { 6556var p = document.createElement('div'); 6557p.setAttribute('class', 'new_option_id_entry'); 6558var c0b = document.createElement('input'); 6559c0b.setAttribute('type', 'text'); 6560c0b.setAttribute('onchange', 'attribute_property_on_option_add(this)'); 6561c0b.setAttribute('id', '_via_attribute_new_option_id'); 6562c0b.setAttribute('placeholder', 'Add new option id'); 6563p.appendChild(c0b); 6564document.getElementById('attribute_options').appendChild(p); 6565} 6566 6567function attribute_property_on_update(p) { 6568var attr_id = get_current_attribute_id(); 6569var attr_type = _via_attribute_being_updated; 6570var new_attr_type = p.value; 6571 6572switch(p.id) { 6573case 'attribute_name': 6574if ( new_attr_type !== attr_id ) { 6575Object.defineProperty(_via_attributes[attr_type], 6576new_attr_type, 6577Object.getOwnPropertyDescriptor(_via_attributes[attr_type], attr_id)); 6578 6579delete _via_attributes[attr_type][attr_id]; 6580update_attributes_update_panel(); 6581annotation_editor_update_content(); 6582} 6583break; 6584case 'attribute_description': 6585_via_attributes[attr_type][attr_id].description = new_attr_type; 6586update_attributes_update_panel(); 6587annotation_editor_update_content(); 6588break; 6589case 'attribute_default_value': 6590_via_attributes[attr_type][attr_id].default_value = new_attr_type; 6591update_attributes_update_panel(); 6592annotation_editor_update_content(); 6593break; 6594case 'attribute_type': 6595var old_attr_type = _via_attributes[attr_type][attr_id].type; 6596_via_attributes[attr_type][attr_id].type = new_attr_type; 6597if( new_attr_type === VIA_ATTRIBUTE_TYPE.TEXT ) { 6598_via_attributes[attr_type][attr_id].default_value = ''; 6599delete _via_attributes[attr_type][attr_id].options; 6600delete _via_attributes[attr_type][attr_id].default_options; 6601} else { 6602// add options entry (if missing) 6603if ( ! _via_attributes[attr_type][attr_id].hasOwnProperty('options') ) { 6604_via_attributes[attr_type][attr_id].options = {}; 6605_via_attributes[attr_type][attr_id].default_options = {}; 6606} 6607if ( _via_attributes[attr_type][attr_id].hasOwnProperty('default_value') ) { 6608delete _via_attributes[attr_type][attr_id].default_value; 6609} 6610 6611// 1. gather all the attribute values in existing metadata 6612var existing_attr_values = attribute_get_unique_values(attr_type, attr_id); 6613 6614// 2. for checkbox, radio, dropdown: create options based on existing options and existing values 6615for(var option_id in _via_attributes[attr_type][attr_id]['options']) { 6616if( !existing_attr_values.includes(option_id) ) { 6617_via_attributes[attr_type][attr_id]['options'][option_id] = option_id; 6618} 6619} 6620 6621// update existing metadata to reflect changes in attribute type 6622// ensure that attribute has only one value 6623for(var img_id in _via_img_metadata ) { 6624for(var rindex in _via_img_metadata[img_id]['regions']) { 6625if(_via_img_metadata[img_id]['regions'][rindex]['region_attributes'].hasOwnProperty(attr_id)) { 6626if(old_attr_type === VIA_ATTRIBUTE_TYPE.CHECKBOX && 6627(new_attr_type === VIA_ATTRIBUTE_TYPE.RADIO || 6628new_attr_type === VIA_ATTRIBUTE_TYPE.DROPDOWN) ) { 6629// add only if checkbox has only single option selected 6630var sel_option_count = 0; 6631var sel_option_id; 6632for(var option_id in _via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id]) { 6633if(_via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id][option_id]) { 6634sel_option_count = sel_option_count + 1; 6635sel_option_id = option_id; 6636} 6637} 6638if(sel_option_count === 1) { 6639_via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id] = sel_option_id; 6640} else { 6641// delete as multiple options cannot be represented as radio or dropdown 6642delete _via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id]; 6643} 6644} 6645if( (old_attr_type === VIA_ATTRIBUTE_TYPE.RADIO || 6646old_attr_type === VIA_ATTRIBUTE_TYPE.DROPDOWN) && 6647new_attr_type === VIA_ATTRIBUTE_TYPE.CHECKBOX) { 6648var old_option_id = _via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id]; 6649_via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id] = {}; 6650_via_img_metadata[img_id]['regions'][rindex]['region_attributes'][attr_id][old_option_id] = true; 6651} 6652} 6653} 6654} 6655} 6656show_attribute_properties(); 6657show_attribute_options(); 6658annotation_editor_update_content(); 6659break; 6660} 6661} 6662 6663function attribute_get_unique_values(attr_type, attr_id) { 6664var values = []; 6665switch ( attr_type ) { 6666case 'file': 6667var img_id, attr_val; 6668for ( img_id in _via_img_metadata ) { 6669if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty(attr_id) ) { 6670attr_val = _via_img_metadata[img_id].file_attributes[attr_id]; 6671if ( ! values.includes(attr_val) ) { 6672values.push(attr_val); 6673} 6674} 6675} 6676break; 6677case 'region': 6678var img_id, attr_val, i; 6679for ( img_id in _via_img_metadata ) { 6680for ( i = 0; i < _via_img_metadata[img_id].regions.length; ++i ) { 6681if ( _via_img_metadata[img_id].regions[i].region_attributes.hasOwnProperty(attr_id) ) { 6682attr_val = _via_img_metadata[img_id].regions[i].region_attributes[attr_id]; 6683if( typeof(attr_val) === 'object' ) { 6684for(var option_id in _via_img_metadata[img_id].regions[i].region_attributes[attr_id]) { 6685if ( ! values.includes(option_id) ) { 6686values.push(option_id); 6687} 6688} 6689} else { 6690if ( ! values.includes(attr_val) ) { 6691values.push(attr_val); 6692} 6693} 6694} 6695} 6696} 6697break; 6698default: 6699break; 6700} 6701return values; 6702} 6703 6704function attribute_property_on_option_update(p) { 6705var attr_id = get_current_attribute_id(); 6706if ( p.id.startsWith('_via_attribute_option_id_') ) { 6707var old_key = p.id.substr( '_via_attribute_option_id_'.length ); 6708var new_key = p.value; 6709if ( old_key !== new_key ) { 6710var option_id_test = attribute_property_option_id_is_valid(attr_id, new_key); 6711if ( option_id_test.is_valid ) { 6712update_attribute_option_id_with_confirm(_via_attribute_being_updated, 6713attr_id, 6714old_key, 6715new_key); 6716} else { 6717p.value = old_key; // restore old value 6718show_message( option_id_test.message ); 6719show_attribute_properties(); 6720} 6721return; 6722} 6723} 6724 6725if ( p.id.startsWith('_via_attribute_option_description_') ) { 6726var key = p.id.substr( '_via_attribute_option_description_'.length ); 6727var old_value = _via_attributes[_via_attribute_being_updated][attr_id].options[key]; 6728var new_value = p.value; 6729if ( new_value !== old_value ) { 6730_via_attributes[_via_attribute_being_updated][attr_id].options[key] = new_value; 6731show_attribute_properties(); 6732annotation_editor_update_content(); 6733} 6734} 6735 6736if ( p.id.startsWith('_via_attribute_option_default_') ) { 6737var new_default_option_id = p.id.substr( '_via_attribute_option_default_'.length ); 6738var old_default_option_id_list = Object.keys(_via_attributes[_via_attribute_being_updated][attr_id].default_options); 6739 6740if ( old_default_option_id_list.length === 0 ) { 6741// default set for the first time 6742_via_attributes[_via_attribute_being_updated][attr_id].default_options[new_default_option_id] = p.checked; 6743} else { 6744switch ( _via_attributes[_via_attribute_being_updated][attr_id].type ) { 6745case 'image': // fallback 6746case 'dropdown': // fallback 6747case 'radio': // fallback 6748// to ensure that only one radio button is selected at a time 6749_via_attributes[_via_attribute_being_updated][attr_id].default_options = {}; 6750_via_attributes[_via_attribute_being_updated][attr_id].default_options[new_default_option_id] = p.checked; 6751break; 6752case 'checkbox': 6753_via_attributes[_via_attribute_being_updated][attr_id].default_options[new_default_option_id] = p.checked; 6754break; 6755} 6756} 6757// default option updated 6758attribute_property_on_option_default_update(_via_attribute_being_updated, 6759attr_id, 6760new_default_option_id).then( function() { 6761show_attribute_properties(); 6762annotation_editor_update_content(); 6763}); 6764} 6765} 6766 6767function attribute_property_on_option_default_update(attribute_being_updated, attr_id, new_default_option_id) { 6768return new Promise( function(ok_callback, err_callback) { 6769// set all metadata to new_value if: 6770// - metadata[attr_id] is missing 6771// - metadata[attr_id] is set to option_old_value 6772var img_id, attr_value, n, i; 6773var attr_type = _via_attributes[attribute_being_updated][attr_id].type; 6774switch( attribute_being_updated ) { 6775case 'file': 6776for ( img_id in _via_img_metadata ) { 6777if ( ! _via_img_metadata[img_id].file_attributes.hasOwnProperty(attr_id) ) { 6778_via_img_metadata[img_id].file_attributes[attr_id] = new_default_option_id; 6779} 6780} 6781break; 6782case 'region': 6783for ( img_id in _via_img_metadata ) { 6784n = _via_img_metadata[img_id].regions.length; 6785for ( i = 0; i < n; ++i ) { 6786if ( ! _via_img_metadata[img_id].regions[i].region_attributes.hasOwnProperty(attr_id) ) { 6787_via_img_metadata[img_id].regions[i].region_attributes[attr_id] = new_default_option_id; 6788} 6789} 6790} 6791break; 6792} 6793ok_callback(); 6794}); 6795} 6796 6797function attribute_property_on_option_add(p) { 6798if ( p.value === '' || p.value === null ) { 6799return; 6800} 6801 6802if ( p.id === '_via_attribute_new_option_id' ) { 6803var attr_id = get_current_attribute_id(); 6804var option_id = p.value; 6805var option_id_test = attribute_property_option_id_is_valid(attr_id, option_id); 6806if ( option_id_test.is_valid ) { 6807_via_attributes[_via_attribute_being_updated][attr_id].options[option_id] = ''; 6808show_attribute_options(); 6809annotation_editor_update_content(); 6810} else { 6811show_message( option_id_test.message ); 6812attribute_property_reset_new_entry_inputs(); 6813} 6814} 6815} 6816 6817function attribute_property_reset_new_entry_inputs() { 6818var container = document.getElementById('attribute_options'); 6819var p = container.lastChild; 6820if ( p.childNodes[0] ) { 6821p.childNodes[0].value = ''; 6822} 6823if ( p.childNodes[1] ) { 6824p.childNodes[1].value = ''; 6825} 6826} 6827 6828function attribute_property_show_new_entry_inputs(attr_id, attribute_type) { 6829var n0 = document.createElement('div'); 6830n0.classList.add('property'); 6831var n1a = document.createElement('span'); 6832var n1b = document.createElement('input'); 6833n1b.setAttribute('onchange', 'attribute_property_on_option_add(this)'); 6834n1b.setAttribute('placeholder', 'Add new id'); 6835n1b.setAttribute('value', ''); 6836n1b.setAttribute('id', '_via_attribute_new_option_id'); 6837n1a.appendChild(n1b); 6838 6839var n2a = document.createElement('span'); 6840var n2b = document.createElement('input'); 6841n2b.setAttribute('onchange', 'attribute_property_on_option_add(this)'); 6842n2b.setAttribute('placeholder', 'Optional description'); 6843n2b.setAttribute('value', ''); 6844n2b.setAttribute('id', '_via_attribute_new_option_description'); 6845n2a.appendChild(n2b); 6846 6847var n3a = document.createElement('span'); 6848var n3b = document.createElement('input'); 6849n3b.setAttribute('type', attribute_type); 6850if ( attribute_type === 'radio' ) { 6851n3b.setAttribute('name', attr_id); 6852} 6853n3b.setAttribute('onchange', 'attribute_property_on_option_add(this)'); 6854n3b.setAttribute('id', '_via_attribute_new_option_default'); 6855n3a.appendChild(n3b); 6856 6857n0.appendChild(n1a); 6858n0.appendChild(n2a); 6859n0.appendChild(n3a); 6860 6861var container = document.getElementById('attribute_options'); 6862container.appendChild(n0); 6863} 6864 6865function attribute_property_option_id_is_valid(attr_id, new_option_id) { 6866var option_id; 6867for ( option_id in _via_attributes[_via_attribute_being_updated][attr_id].options ) { 6868if ( option_id === new_option_id ) { 6869return { 'is_valid':false, 'message':'Option id [' + attr_id + '] already exists' }; 6870} 6871} 6872 6873if ( new_option_id.includes('__') ) { // reserved separator for attribute-id, row-id, option-id 6874return {'is_valid':false, 'message':'Option id cannot contain two consecutive underscores'}; 6875} 6876 6877return {'is_valid':true}; 6878} 6879 6880function attribute_property_id_exists(name) { 6881var attr_name; 6882for ( attr_name in _via_attributes[_via_attribute_being_updated] ) { 6883if ( attr_name === name ) { 6884return true; 6885} 6886} 6887return false; 6888} 6889 6890function delete_existing_attribute_with_confirm() { 6891var attr_id = document.getElementById('user_input_attribute_id').value; 6892if ( attr_id === '' ) { 6893show_message('Enter the name of attribute that you wish to delete'); 6894return; 6895} 6896if ( attribute_property_id_exists(attr_id) ) { 6897var config = {'title':'Delete ' + _via_attribute_being_updated + ' attribute [' + attr_id + ']', 6898'warning': 'Warning: Deleting an attribute will lead to the attribute being deleted in all the annotations. Please click OK only if you are sure.'}; 6899var input = { 'attr_type':{'type':'text', 'name':'Attribute Type', 'value':_via_attribute_being_updated, 'disabled':true}, 6900'attr_id':{'type':'text', 'name':'Attribute Id', 'value':attr_id, 'disabled':true} 6901}; 6902invoke_with_user_inputs(delete_existing_attribute_confirmed, input, config); 6903} else { 6904show_message('Attribute [' + attr_id + '] does not exist!'); 6905return; 6906} 6907} 6908 6909function delete_existing_attribute_confirmed(input) { 6910var attr_type = input.attr_type.value; 6911var attr_id = input.attr_id.value; 6912delete_existing_attribute(attr_type, attr_id); 6913document.getElementById('user_input_attribute_id').value = ''; 6914show_message('Deleted ' + attr_type + ' attribute [' + attr_id + ']'); 6915user_input_default_cancel_handler(); 6916} 6917 6918function delete_existing_attribute(attribute_type, attr_id) { 6919if ( _via_attributes[attribute_type].hasOwnProperty( attr_id ) ) { 6920var attr_id_list = Object.keys(_via_attributes[attribute_type]); 6921if ( attr_id_list.length === 1 ) { 6922_via_current_attribute_id = ''; 6923} else { 6924var current_index = attr_id_list.indexOf(attr_id); 6925var next_index = current_index + 1; 6926if ( next_index === attr_id_list.length ) { 6927next_index = current_index - 1; 6928} 6929_via_current_attribute_id = attr_id_list[next_index]; 6930} 6931delete _via_attributes[attribute_type][attr_id]; 6932delete_region_attribute_in_all_metadata(attr_id); 6933update_attributes_update_panel(); 6934annotation_editor_update_content(); 6935} 6936} 6937 6938function add_new_attribute_from_user_input() { 6939var attr_id = document.getElementById('user_input_attribute_id').value; 6940if ( attr_id === '' ) { 6941show_message('Enter the name of attribute that you wish to delete'); 6942return; 6943} 6944 6945if ( attribute_property_id_exists(attr_id) ) { 6946show_message('The ' + _via_attribute_being_updated + ' attribute [' + attr_id + '] already exists.'); 6947} else { 6948_via_current_attribute_id = attr_id; 6949add_new_attribute(attr_id); 6950update_attributes_update_panel(); 6951annotation_editor_update_content(); 6952show_message('Added ' + _via_attribute_being_updated + ' attribute [' + attr_id + '].'); 6953} 6954} 6955 6956function add_new_attribute(attribute_id) { 6957_via_attributes[_via_attribute_being_updated][attribute_id] = {}; 6958_via_attributes[_via_attribute_being_updated][attribute_id].type = 'text'; 6959_via_attributes[_via_attribute_being_updated][attribute_id].description = ''; 6960_via_attributes[_via_attribute_being_updated][attribute_id].default_value = ''; 6961} 6962 6963function update_current_attribute_id(p) { 6964_via_current_attribute_id = p.options[p.selectedIndex].value; 6965update_attribute_properties_panel(); 6966} 6967 6968function get_current_attribute_id() { 6969return document.getElementById('attributes_name_list').value; 6970} 6971 6972function update_attribute_option_id_with_confirm(attr_type, attr_id, option_id, new_option_id) { 6973var is_delete = false; 6974var config; 6975if ( new_option_id === '' || typeof(new_option_id) === 'undefined' ) { 6976// an empty new_option_id indicates deletion of option_id 6977config = {'title':'Delete an option for ' + attr_type + ' attribute'}; 6978is_delete = true; 6979} else { 6980config = {'title':'Rename an option for ' + attr_type + ' attribute'}; 6981} 6982 6983var input = { 'attr_type':{'type':'text', 'name':'Attribute Type', 'value':attr_type, 'disabled':true}, 6984'attr_id':{'type':'text', 'name':'Attribute Id', 'value':attr_id, 'disabled':true} 6985}; 6986 6987if ( is_delete ) { 6988input['option_id'] = {'type':'text', 'name':'Attribute Option', 'value':option_id, 'disabled':true}; 6989} else { 6990input['option_id'] = {'type':'text', 'name':'Attribute Option (old)', 'value':option_id, 'disabled':true}, 6991input['new_option_id'] = {'type':'text', 'name':'Attribute Option (new)', 'value':new_option_id, 'disabled':true}; 6992} 6993 6994invoke_with_user_inputs(update_attribute_option_id_confirmed, input, config, update_attribute_option_id_cancel); 6995} 6996 6997function update_attribute_option_id_cancel(input) { 6998update_attribute_properties_panel(); 6999} 7000 7001function update_attribute_option_id_confirmed(input) { 7002var attr_type = input.attr_type.value; 7003var attr_id = input.attr_id.value; 7004var option_id = input.option_id.value; 7005var is_delete; 7006var new_option_id; 7007if ( typeof(input.new_option_id) === 'undefined' || input.new_option_id === '' ) { 7008is_delete = true; 7009new_option_id = ''; 7010} else { 7011is_delete = false; 7012new_option_id = input.new_option_id.value; 7013} 7014 7015update_attribute_option(is_delete, attr_type, attr_id, option_id, new_option_id); 7016 7017if ( is_delete ) { 7018show_message('Deleted option [' + option_id + '] for ' + attr_type + ' attribute [' + attr_id + '].'); 7019} else { 7020show_message('Renamed option [' + option_id + '] to [' + new_option_id + '] for ' + attr_type + ' attribute [' + attr_id + '].'); 7021} 7022update_attribute_properties_panel(); 7023annotation_editor_update_content(); 7024user_input_default_cancel_handler(); 7025} 7026 7027function update_attribute_option(is_delete, attr_type, attr_id, option_id, new_option_id) { 7028switch ( attr_type ) { 7029case 'region': 7030update_region_attribute_option_in_all_metadata(is_delete, attr_id, option_id, new_option_id); 7031if ( ! is_delete ) { 7032Object.defineProperty(_via_attributes[attr_type][attr_id].options, 7033new_option_id, 7034Object.getOwnPropertyDescriptor(_via_attributes[_via_attribute_being_updated][attr_id].options, option_id)); 7035} 7036delete _via_attributes['region'][attr_id].options[option_id]; 7037 7038break; 7039case 'file': 7040update_file_attribute_option_in_all_metadata(attr_id, option_id); 7041if ( ! is_delete ) { 7042Object.defineProperty(_via_attributes[attr_type][attr_id].options, 7043new_option_id, 7044Object.getOwnPropertyDescriptor(_via_attributes[_via_attribute_being_updated][attr_id].options, option_id)); 7045} 7046 7047delete _via_attributes['file'][attr_id].options[option_id]; 7048break; 7049} 7050} 7051 7052function update_file_attribute_option_in_all_metadata(is_delete, attr_id, option_id, new_option_id) { 7053var image_id; 7054for ( image_id in _via_img_metadata ) { 7055if ( _via_img_metadata[image_id].file_attributes.hasOwnProperty(attr_id) ) { 7056if ( _via_img_metadata[image_id].file_attributes[attr_id].hasOwnProperty(option_id) ) { 7057Object.defineProperty(_via_img_metadata[image_id].file_attributes[attr_id], 7058new_option_id, 7059Object.getOwnPropertyDescriptor(_via_img_metadata[image_id].file_attributes[attr_id], option_id)); 7060delete _via_img_metadata[image_id].file_attributes[attr_id][option_id]; 7061} 7062} 7063} 7064} 7065 7066function update_region_attribute_option_in_all_metadata(is_delete, attr_id, option_id, new_option_id) { 7067var image_id; 7068for ( image_id in _via_img_metadata ) { 7069for (var i = 0; i < _via_img_metadata[image_id].regions.length; ++i ) { 7070if ( _via_img_metadata[image_id].regions[i].region_attributes.hasOwnProperty(attr_id) ) { 7071if ( _via_img_metadata[image_id].regions[i].region_attributes[attr_id].hasOwnProperty(option_id) ) { 7072Object.defineProperty(_via_img_metadata[image_id].regions[i].region_attributes[attr_id], 7073new_option_id, 7074Object.getOwnPropertyDescriptor(_via_img_metadata[image_id].regions[i].region_attributes[attr_id], option_id)); 7075delete _via_img_metadata[image_id].regions[i].region_attributes[attr_id][option_id]; 7076} 7077} 7078} 7079} 7080} 7081 7082function delete_region_attribute_in_all_metadata(attr_id) { 7083var image_id; 7084for ( image_id in _via_img_metadata ) { 7085for (var i = 0; i < _via_img_metadata[image_id].regions.length; ++i ) { 7086if ( _via_img_metadata[image_id].regions[i].region_attributes.hasOwnProperty(attr_id)) { 7087delete _via_img_metadata[image_id].regions[i].region_attributes[attr_id]; 7088} 7089} 7090} 7091} 7092 7093function delete_file_attribute_option_from_all_metadata(attr_id, option_id) { 7094var image_id; 7095for ( image_id in _via_img_metadata ) { 7096if ( _via_img_metadata.hasOwnProperty(image_id) ) { 7097delete_file_attribute_option_from_metadata(image_id, attr_id, option_id); 7098} 7099} 7100} 7101 7102function delete_file_attribute_option_from_metadata(image_id, attr_id, option_id) { 7103var i; 7104if ( _via_img_metadata[image_id].file_attributes.hasOwnProperty(attr_id) ) { 7105if ( _via_img_metadata[image_id].file_attributes[attr_id].hasOwnProperty(option_id) ) { 7106delete _via_img_metadata[image_id].file_attributes[attr_id][option_id]; 7107} 7108} 7109} 7110 7111function delete_file_attribute_from_all_metadata(image_id, attr_id) { 7112var image_id; 7113for ( image_id in _via_img_metadata ) { 7114if ( _via_img_metadata.hasOwnProperty(image_id) ) { 7115if ( _via_img_metadata[image_id].file_attributes.hasOwnProperty(attr_id) ) { 7116delete _via_img_metadata[image_id].file_attributes[attr_id]; 7117} 7118} 7119} 7120} 7121 7122// 7123// invoke a method after receiving inputs from user 7124// 7125function invoke_with_user_inputs(ok_handler, input, config, cancel_handler) { 7126setup_user_input_panel(ok_handler, input, config, cancel_handler); 7127show_user_input_panel(); 7128} 7129 7130function setup_user_input_panel(ok_handler, input, config, cancel_handler) { 7131// create html page with OK and CANCEL button 7132// when OK is clicked 7133// - setup input with all the user entered values 7134// - invoke handler with input 7135// when CANCEL is clicked 7136// - invoke user_input_cancel() 7137_via_user_input_ok_handler = ok_handler; 7138_via_user_input_cancel_handler = cancel_handler; 7139_via_user_input_data = input; 7140 7141var p = document.getElementById('user_input_panel'); 7142var c = document.createElement('div'); 7143c.setAttribute('class', 'content'); 7144var html = []; 7145html.push('<p class="title">' + config.title + '</p>'); 7146 7147html.push('<div class="user_inputs">'); 7148var key; 7149for ( key in _via_user_input_data ) { 7150html.push('<div class="row">'); 7151html.push('<span class="cell">' + _via_user_input_data[key].name + '</span>'); 7152var disabled_html = ''; 7153if ( _via_user_input_data[key].disabled ) { 7154disabled_html = 'disabled="disabled"'; 7155} 7156var value_html = ''; 7157if ( _via_user_input_data[key].value ) { 7158value_html = 'value="' + _via_user_input_data[key].value + '"'; 7159} 7160 7161switch(_via_user_input_data[key].type) { 7162case 'checkbox': 7163if ( _via_user_input_data[key].checked ) { 7164value_html = 'checked="checked"'; 7165} else { 7166value_html = ''; 7167} 7168html.push('<span class="cell">' + 7169'<input class="_via_user_input_variable" ' + 7170value_html + ' ' + 7171disabled_html + ' ' + 7172'type="checkbox" id="' + key + '"></span>'); 7173break; 7174case 'text': 7175var size = '50'; 7176if ( _via_user_input_data[key].size ) { 7177size = _via_user_input_data[key].size; 7178} 7179var placeholder = ''; 7180if ( _via_user_input_data[key].placeholder ) { 7181placeholder = _via_user_input_data[key].placeholder; 7182} 7183html.push('<span class="cell">' + 7184'<input class="_via_user_input_variable" ' + 7185value_html + ' ' + 7186disabled_html + ' ' + 7187'size="' + size + '" ' + 7188'placeholder="' + placeholder + '" ' + 7189'type="text" id="' + key + '"></span>'); 7190 7191break; 7192case 'textarea': 7193var rows = '5'; 7194var cols = '50' 7195if ( _via_user_input_data[key].rows ) { 7196rows = _via_user_input_data[key].rows; 7197} 7198if ( _via_user_input_data[key].cols ) { 7199cols = _via_user_input_data[key].cols; 7200} 7201var placeholder = ''; 7202if ( _via_user_input_data[key].placeholder ) { 7203placeholder = _via_user_input_data[key].placeholder; 7204} 7205html.push('<span class="cell">' + 7206'<textarea class="_via_user_input_variable" ' + 7207disabled_html + ' ' + 7208'rows="' + rows + '" ' + 7209'cols="' + cols + '" ' + 7210'placeholder="' + placeholder + '" ' + 7211'id="' + key + '">' + value_html + '</textarea></span>'); 7212 7213break; 7214 7215} 7216html.push('</div>'); // end of row 7217} 7218html.push('</div>'); // end of user_input div 7219// optional warning before confirmation 7220if (config.hasOwnProperty("warning") ) { 7221html.push('<div class="warning">' + config.warning + '</div>'); 7222} 7223html.push('<div class="user_confirm">' + 7224'<span class="ok">' + 7225'<button id="user_input_ok_button" onclick="user_input_parse_and_invoke_handler()"> OK </button></span>' + 7226'<span class="cancel">' + 7227'<button id="user_input_cancel_button" onclick="user_input_cancel_handler()">CANCEL</button></span></div>'); 7228c.innerHTML = html.join(''); 7229p.innerHTML = ''; 7230p.appendChild(c); 7231 7232} 7233 7234function user_input_default_cancel_handler() { 7235hide_user_input_panel(); 7236_via_user_input_data = {}; 7237_via_user_input_ok_handler = null; 7238_via_user_input_cancel_handler = null; 7239} 7240 7241function user_input_cancel_handler() { 7242if ( _via_user_input_cancel_handler ) { 7243_via_user_input_cancel_handler(); 7244} 7245user_input_default_cancel_handler(); 7246} 7247 7248function user_input_parse_and_invoke_handler() { 7249var elist = document.getElementsByClassName('_via_user_input_variable'); 7250var i; 7251for ( i=0; i < elist.length; ++i ) { 7252var eid = elist[i].id; 7253if ( _via_user_input_data.hasOwnProperty(eid) ) { 7254switch(_via_user_input_data[eid].type) { 7255case 'checkbox': 7256_via_user_input_data[eid].value = elist[i].checked; 7257break; 7258default: 7259_via_user_input_data[eid].value = elist[i].value; 7260break; 7261} 7262} 7263} 7264if ( typeof(_via_user_input_data.confirm) !== 'undefined' ) { 7265if ( _via_user_input_data.confirm.value ) { 7266_via_user_input_ok_handler(_via_user_input_data); 7267} else { 7268if ( _via_user_input_cancel_handler ) { 7269_via_user_input_cancel_handler(); 7270} 7271} 7272} else { 7273_via_user_input_ok_handler(_via_user_input_data); 7274} 7275user_input_default_cancel_handler(); 7276} 7277 7278function show_user_input_panel() { 7279document.getElementById('user_input_panel').style.display = 'block'; 7280} 7281 7282function hide_user_input_panel() { 7283document.getElementById('user_input_panel').style.display = 'none'; 7284} 7285 7286// 7287// annotations editor panel 7288// 7289function annotation_editor_show() { 7290// remove existing annotation editor (if any) 7291annotation_editor_remove(); 7292 7293// create new container of annotation editor 7294var ae = document.createElement('div'); 7295ae.setAttribute('id', 'annotation_editor'); 7296 7297if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION ) { 7298if ( _via_settings.ui.image.on_image_annotation_editor_placement === VIA_ANNOTATION_EDITOR_PLACEMENT.DISABLE ) { 7299return; 7300} 7301 7302// only display on-image annotation editor if 7303// - region attribute are defined 7304// - region is selected 7305if ( _via_is_region_selected && 7306Object.keys(_via_attributes['region']).length && 7307_via_attributes['region'].constructor === Object ) { 7308ae.classList.add('force_small_font'); 7309ae.classList.add('display_area_content'); // to enable automatic hiding of this content 7310// add annotation editor to image_panel 7311if ( _via_settings.ui.image.on_image_annotation_editor_placement === VIA_ANNOTATION_EDITOR_PLACEMENT.NEAR_REGION ) { 7312var html_position = annotation_editor_get_placement(_via_user_sel_region_id); 7313ae.style.top = html_position.top; 7314ae.style.left = html_position.left; 7315} 7316_via_display_area.appendChild(ae); 7317annotation_editor_update_content(); 7318update_vertical_space(); 7319} 7320} else { 7321// show annotation editor in a separate panel at the bottom 7322_via_annotaion_editor_panel.appendChild(ae); 7323annotation_editor_update_content(); 7324update_vertical_space(); 7325 7326if ( _via_is_region_selected ) { 7327// highlight entry for region_id in annotation editor panel 7328annotation_editor_scroll_to_row(_via_user_sel_region_id); 7329annotation_editor_highlight_row(_via_user_sel_region_id); 7330} 7331} 7332} 7333 7334function annotation_editor_hide() { 7335if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION ) { 7336// remove existing annotation editor (if any) 7337annotation_editor_remove(); 7338} else { 7339annotation_editor_clear_row_highlight(); 7340} 7341} 7342 7343function annotation_editor_toggle_on_image_editor() { 7344if ( _via_settings.ui.image.on_image_annotation_editor_placement === VIA_ANNOTATION_EDITOR_PLACEMENT.DISABLE ) { 7345_via_annotation_editor_mode = VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION; 7346_via_settings.ui.image.on_image_annotation_editor_placement = VIA_ANNOTATION_EDITOR_PLACEMENT.NEAR_REGION; 7347annotation_editor_show(); 7348show_message('Enabled on image annotation editor'); 7349} else { 7350_via_settings.ui.image.on_image_annotation_editor_placement = VIA_ANNOTATION_EDITOR_PLACEMENT.DISABLE; 7351_via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.ALL_REGIONS; 7352annotation_editor_hide(); 7353show_message('Disabled on image annotation editor'); 7354} 7355} 7356 7357function annotation_editor_update_content() { 7358return new Promise( function(ok_callback, err_callback) { 7359var ae = document.getElementById('annotation_editor'); 7360if (ae ) { 7361ae.innerHTML = ''; 7362annotation_editor_update_header_html(); 7363annotation_editor_update_metadata_html(); 7364} 7365ok_callback(); 7366}); 7367} 7368 7369function annotation_editor_get_placement(region_id) { 7370var html_position = {}; 7371var r = _via_canvas_regions[region_id]['shape_attributes']; 7372var shape = r['name']; 7373switch( shape ) { 7374case 'rect': 7375html_position.top = r['y'] + r['height']; 7376html_position.left = r['x'] + r['width']; 7377break; 7378case 'circle': 7379html_position.top = r['cy'] + r['r']; 7380html_position.left = r['cx']; 7381break; 7382case 'ellipse': 7383html_position.top = r['cy'] + r['ry'] * Math.cos(r['theta']); 7384html_position.left = r['cx'] - r['ry'] * Math.sin(r['theta']); 7385break; 7386case 'polygon': 7387case 'polyline': 7388var most_left = 7389Object.keys(r['all_points_x']).reduce(function(a, b){ 7390return r['all_points_x'][a] > r['all_points_x'][b] ? a : b }); 7391html_position.top = Math.max( r['all_points_y'][most_left] ); 7392html_position.left = Math.max( r['all_points_x'][most_left] ); 7393break; 7394case 'point': 7395html_position.top = r['cy']; 7396html_position.left = r['cx']; 7397break; 7398} 7399html_position.top = html_position.top + _via_img_panel.offsetTop + VIA_REGION_EDGE_TOL + 'px'; 7400html_position.left = html_position.left + _via_img_panel.offsetLeft + VIA_REGION_EDGE_TOL + 'px'; 7401return html_position; 7402} 7403 7404function annotation_editor_remove() { 7405var p = document.getElementById('annotation_editor'); 7406if ( p ) { 7407p.remove(); 7408} 7409} 7410 7411function is_annotation_editor_visible() { 7412return document.getElementById('annotation_editor_panel').classList.contains('display_block'); 7413} 7414 7415function annotation_editor_toggle_all_regions_editor() { 7416var p = document.getElementById('annotation_editor_panel'); 7417if ( p.classList.contains('display_block') ) { 7418p.classList.remove('display_block'); 7419_via_annotation_editor_mode = VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION; 7420} else { 7421_via_annotation_editor_mode = VIA_ANNOTATION_EDITOR_MODE.ALL_REGIONS; 7422p.classList.add('display_block'); 7423p.style.height = _via_settings.ui.annotation_editor_height + '%'; 7424p.style.fontSize = _via_settings.ui.annotation_editor_fontsize + 'rem'; 7425annotation_editor_show(); 7426} 7427} 7428 7429function annotation_editor_set_active_button() { 7430var attribute_type; 7431for ( attribute_type in _via_attributes ) { 7432var bid = 'button_edit_' + attribute_type + '_metadata'; 7433document.getElementById(bid).classList.remove('active'); 7434} 7435var bid = 'button_edit_' + _via_metadata_being_updated + '_metadata'; 7436document.getElementById(bid).classList.add('active'); 7437} 7438 7439function edit_region_metadata_in_annotation_editor() { 7440_via_metadata_being_updated = 'region'; 7441annotation_editor_set_active_button(); 7442annotation_editor_update_content(); 7443} 7444function edit_file_metadata_in_annotation_editor() { 7445_via_metadata_being_updated = 'file'; 7446annotation_editor_set_active_button(); 7447annotation_editor_update_content(); 7448} 7449 7450function annotation_editor_update_header_html() { 7451var head = document.createElement('div'); 7452head.setAttribute('class', 'row'); 7453head.setAttribute('id', 'annotation_editor_header'); 7454 7455if ( _via_metadata_being_updated === 'region' ) { 7456var rid_col = document.createElement('span'); 7457rid_col.setAttribute('class', 'col'); 7458rid_col.innerHTML = ''; 7459head.appendChild(rid_col); 7460} 7461 7462if ( _via_metadata_being_updated === 'file' ) { 7463var rid_col = document.createElement('span'); 7464rid_col.setAttribute('class', 'col header'); 7465if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 7466rid_col.innerHTML = 'group'; 7467} else { 7468rid_col.innerHTML = 'filename'; 7469} 7470head.appendChild(rid_col); 7471} 7472 7473var attr_id; 7474for ( attr_id in _via_attributes[_via_metadata_being_updated] ) { 7475var col = document.createElement('span'); 7476col.setAttribute('class', 'col header'); 7477col.innerHTML = attr_id; 7478head.appendChild(col); 7479} 7480 7481var ae = document.getElementById('annotation_editor'); 7482if ( ae.childNodes.length === 0 ) { 7483ae.appendChild(head); 7484} else { 7485if ( ae.firstChild.id === 'annotation_editor_header') { 7486ae.replaceChild(head, ae.firstChild); 7487} else { 7488// header node is absent 7489ae.insertBefore(head, ae.firstChild); 7490} 7491} 7492} 7493 7494function annotation_editor_update_metadata_html() { 7495if ( ! _via_img_count ) { 7496return; 7497} 7498 7499var ae = document.getElementById('annotation_editor'); 7500switch ( _via_metadata_being_updated ) { 7501case 'region': 7502var rindex; 7503if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 7504ae.appendChild( annotation_editor_get_metadata_row_html(0) ); 7505} else { 7506if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE ) { 7507if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.SINGLE_REGION ) { 7508ae.appendChild( annotation_editor_get_metadata_row_html(_via_user_sel_region_id) ); 7509} else { 7510for ( rindex = 0; rindex < _via_img_metadata[_via_image_id].regions.length; ++rindex ) { 7511ae.appendChild( annotation_editor_get_metadata_row_html(rindex) ); 7512} 7513} 7514} 7515} 7516break; 7517 7518case 'file': 7519ae.appendChild( annotation_editor_get_metadata_row_html(0) ); 7520break; 7521} 7522} 7523 7524function annotation_editor_update_row(row_id) { 7525var ae = document.getElementById('annotation_editor'); 7526 7527var new_row = annotation_editor_get_metadata_row_html(row_id); 7528var old_row = document.getElementById(new_row.getAttribute('id')); 7529ae.replaceChild(new_row, old_row); 7530} 7531 7532function annotation_editor_add_row(row_id) { 7533if ( is_annotation_editor_visible() ) { 7534var ae = document.getElementById('annotation_editor'); 7535var new_row = annotation_editor_get_metadata_row_html(row_id); 7536var penultimate_row_id = parseInt(row_id) - 1; 7537if ( penultimate_row_id >= 0 ) { 7538var penultimate_row_html_id = 'ae_' + _via_metadata_being_updated + '_' + penultimate_row_id; 7539var penultimate_row = document.getElementById(penultimate_row_html_id); 7540ae.insertBefore(new_row, penultimate_row.nextSibling); 7541} else { 7542ae.appendChild(new_row); 7543} 7544} 7545} 7546 7547function annotation_editor_get_metadata_row_html(row_id) { 7548var row = document.createElement('div'); 7549row.setAttribute('class', 'row'); 7550row.setAttribute('id', 'ae_' + _via_metadata_being_updated + '_' + row_id); 7551 7552if ( _via_metadata_being_updated === 'region' ) { 7553var rid = document.createElement('span'); 7554 7555switch(_via_display_area_content_name) { 7556case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID: 7557rid.setAttribute('class', 'col'); 7558rid.innerHTML = 'Grouped regions in ' + _via_image_grid_selected_img_index_list.length + ' files'; 7559break; 7560case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE: 7561rid.setAttribute('class', 'col id'); 7562rid.innerHTML = (row_id + 1); 7563break; 7564} 7565row.appendChild(rid); 7566} 7567 7568if ( _via_metadata_being_updated === 'file' ) { 7569var rid = document.createElement('span'); 7570rid.setAttribute('class', 'col'); 7571switch(_via_display_area_content_name) { 7572case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID: 7573rid.innerHTML = 'Group of ' + _via_image_grid_selected_img_index_list.length + ' files'; 7574break; 7575case VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE: 7576rid.innerHTML = _via_image_filename_list[_via_image_index]; 7577break; 7578} 7579 7580row.appendChild(rid); 7581} 7582 7583var attr_id; 7584for ( attr_id in _via_attributes[_via_metadata_being_updated] ) { 7585var col = document.createElement('span'); 7586col.setAttribute('class', 'col'); 7587 7588var attr_type = _via_attributes[_via_metadata_being_updated][attr_id].type; 7589var attr_desc = _via_attributes[_via_metadata_being_updated][attr_id].desc; 7590if ( typeof(attr_desc) === 'undefined' ) { 7591attr_desc = ''; 7592} 7593var attr_html_id = attr_id + '__' + row_id; 7594 7595var attr_value = ''; 7596var attr_placeholder = ''; 7597if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE ) { 7598switch(_via_metadata_being_updated) { 7599case 'region': 7600if ( _via_img_metadata[_via_image_id].regions[row_id].region_attributes.hasOwnProperty(attr_id) ) { 7601attr_value = _via_img_metadata[_via_image_id].regions[row_id].region_attributes[attr_id]; 7602} else { 7603attr_placeholder = 'not defined yet!'; 7604} 7605case 'file': 7606if ( _via_img_metadata[_via_image_id].file_attributes.hasOwnProperty(attr_id) ) { 7607attr_value = _via_img_metadata[_via_image_id].file_attributes[attr_id]; 7608} else { 7609attr_placeholder = 'not defined yet!'; 7610} 7611} 7612} 7613 7614if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 7615var attr_metadata_stat; 7616switch(_via_metadata_being_updated) { 7617case 'region': 7618attr_metadata_stat = _via_get_region_metadata_stat(_via_image_grid_selected_img_index_list, attr_id); 7619break; 7620case 'file': 7621attr_metadata_stat = _via_get_file_metadata_stat(_via_image_grid_selected_img_index_list, attr_id); 7622break; 7623} 7624 7625switch ( attr_type ) { 7626case 'text': 7627if ( attr_metadata_stat.hasOwnProperty(attr_id) ) { 7628var attr_value_set = Object.keys(attr_metadata_stat[attr_id]); 7629if ( attr_value_set.includes('undefined') ) { 7630attr_value = ''; 7631attr_placeholder = 'includes ' + attr_metadata_stat[attr_id]['undefined'] + ' undefined values'; 7632} else { 7633switch( attr_value_set.length ) { 7634case 0: 7635attr_value = ''; 7636attr_placeholder = 'not applicable'; 7637break; 7638case 1: 7639attr_value = attr_value_set[0]; 7640attr_placeholder = ''; 7641break; 7642default: 7643attr_value = ''; 7644attr_placeholder = attr_value_set.length + ' different values: ' + JSON.stringify(attr_value_set).replace(/"/g,'\''); 7645} 7646} 7647} else { 7648attr_value = ''; 7649attr_placeholder = 'not defined yet!'; 7650} 7651break; 7652 7653case 'radio': // fallback 7654case 'dropdown': // fallback 7655case 'image': // fallback 7656if ( attr_metadata_stat.hasOwnProperty(attr_id) ) { 7657var attr_value_set = Object.keys(attr_metadata_stat[attr_id]); 7658if ( attr_value_set.length === 1 ) { 7659attr_value = attr_value_set[0]; 7660} else { 7661attr_value = ''; 7662} 7663} else { 7664attr_value = ''; 7665} 7666break; 7667 7668case 'checkbox': 7669attr_value = {}; 7670if ( attr_metadata_stat.hasOwnProperty(attr_id) ) { 7671var attr_value_set = Object.keys(attr_metadata_stat[attr_id]); 7672var same_count = true; 7673var i, n; 7674var attr_value_curr, attr_value_next; 7675n = attr_value_set.length; 7676for ( i = 0; i < n - 1; ++i ) { 7677attr_value_curr = attr_value_set[i]; 7678attr_value_next = attr_value_set[i+1]; 7679 7680if ( attr_metadata_stat[attr_id][attr_value_curr] !== attr_metadata_stat[attr_id][attr_value_next] ) { 7681same_count = false; 7682break; 7683} 7684} 7685if ( same_count ) { 7686var attr_value_i; 7687for ( attr_value_i in attr_metadata_stat[attr_id] ) { 7688attr_value[attr_value_i] = true; 7689} 7690} 7691} 7692break; 7693} 7694} 7695 7696switch(attr_type) { 7697case 'text': 7698col.innerHTML = '<textarea ' + 7699'onchange="annotation_editor_on_metadata_update(this)" ' + 7700'onfocus="annotation_editor_on_metadata_focus(this)" ' + 7701'title="' + attr_desc + '" ' + 7702'placeholder="' + attr_placeholder + '" ' + 7703'id="' + attr_html_id + '">' + attr_value + '</textarea>'; 7704break; 7705case 'checkbox': 7706var options = _via_attributes[_via_metadata_being_updated][attr_id].options; 7707var option_id; 7708for ( option_id in options ) { 7709var option_html_id = attr_html_id + '__' + option_id; 7710var option = document.createElement('input'); 7711option.setAttribute('type', 'checkbox'); 7712option.setAttribute('value', option_id); 7713option.setAttribute('id', option_html_id); 7714option.setAttribute('onfocus', 'annotation_editor_on_metadata_focus(this)'); 7715option.setAttribute('onchange', 'annotation_editor_on_metadata_update(this)'); 7716 7717var option_desc = _via_attributes[_via_metadata_being_updated][attr_id].options[option_id]; 7718if ( option_desc === '' || typeof(option_desc) === 'undefined' ) { 7719// option description is optional, use option_id when description is not present 7720option_desc = option_id; 7721} 7722 7723// set the value of options based on the user annotations 7724if ( typeof attr_value !== 'undefined') { 7725if ( attr_value.hasOwnProperty(option_id) ) { 7726option.checked = attr_value[option_id]; 7727} 7728} 7729 7730var label = document.createElement('label'); 7731label.setAttribute('for', option_html_id); 7732label.innerHTML = option_desc; 7733 7734var container = document.createElement('span'); 7735container.appendChild(option); 7736container.appendChild(label); 7737col.appendChild(container); 7738} 7739break; 7740case 'radio': 7741var option_id; 7742for ( option_id in _via_attributes[_via_metadata_being_updated][attr_id].options ) { 7743var option_html_id = attr_html_id + '__' + option_id; 7744var option = document.createElement('input'); 7745option.setAttribute('type', 'radio'); 7746option.setAttribute('name', attr_html_id); 7747option.setAttribute('value', option_id); 7748option.setAttribute('id', option_html_id); 7749option.setAttribute('onfocus', 'annotation_editor_on_metadata_focus(this)'); 7750option.setAttribute('onchange', 'annotation_editor_on_metadata_update(this)'); 7751 7752var option_desc = _via_attributes[_via_metadata_being_updated][attr_id].options[option_id]; 7753if ( option_desc === '' || typeof(option_desc) === 'undefined' ) { 7754// option description is optional, use option_id when description is not present 7755option_desc = option_id; 7756} 7757 7758if ( attr_value === option_id ) { 7759option.checked = true; 7760} 7761 7762var label = document.createElement('label'); 7763label.setAttribute('for', option_html_id); 7764label.innerHTML = option_desc; 7765 7766var container = document.createElement('span'); 7767container.appendChild(option); 7768container.appendChild(label); 7769col.appendChild(container); 7770} 7771break; 7772case 'image': 7773var option_id; 7774var option_count = 0; 7775for ( option_id in _via_attributes[_via_metadata_being_updated][attr_id].options ) { 7776option_count = option_count + 1; 7777} 7778var img_options = document.createElement('div'); 7779img_options.setAttribute('class', 'img_options'); 7780col.appendChild(img_options); 7781 7782var option_index = 0; 7783for ( option_id in _via_attributes[_via_metadata_being_updated][attr_id].options ) { 7784var option_html_id = attr_html_id + '__' + option_id; 7785var option = document.createElement('input'); 7786option.setAttribute('type', 'radio'); 7787option.setAttribute('name', attr_html_id); 7788option.setAttribute('value', option_id); 7789option.setAttribute('id', option_html_id); 7790option.setAttribute('onfocus', 'annotation_editor_on_metadata_focus(this)'); 7791option.setAttribute('onchange', 'annotation_editor_on_metadata_update(this)'); 7792 7793var option_desc = _via_attributes[_via_metadata_being_updated][attr_id].options[option_id]; 7794if ( option_desc === '' || typeof(option_desc) === 'undefined' ) { 7795// option description is optional, use option_id when description is not present 7796option_desc = option_id; 7797} 7798 7799if ( attr_value === option_id ) { 7800option.checked = true; 7801} 7802 7803var label = document.createElement('label'); 7804label.setAttribute('for', option_html_id); 7805label.innerHTML = '<img src="' + option_desc + '"><p>' + option_id + '</p>'; 7806 7807var container = document.createElement('span'); 7808container.appendChild(option); 7809container.appendChild(label); 7810img_options.appendChild(container); 7811} 7812break; 7813 7814case 'dropdown': 7815var sel = document.createElement('select'); 7816sel.setAttribute('id', attr_html_id); 7817sel.setAttribute('onfocus', 'annotation_editor_on_metadata_focus(this)'); 7818sel.setAttribute('onchange', 'annotation_editor_on_metadata_update(this)'); 7819var option_id; 7820var option_selected = false; 7821for ( option_id in _via_attributes[_via_metadata_being_updated][attr_id].options ) { 7822var option_html_id = attr_html_id + '__' + option_id; 7823var option = document.createElement('option'); 7824option.setAttribute('value', option_id); 7825 7826var option_desc = _via_attributes[_via_metadata_being_updated][attr_id].options[option_id]; 7827if ( option_desc === '' || typeof(option_desc) === 'undefined' ) { 7828// option description is optional, use option_id when description is not present 7829option_desc = option_id; 7830} 7831 7832if ( option_id === attr_value ) { 7833option.setAttribute('selected', 'selected'); 7834option_selected = true; 7835} 7836option.innerHTML = option_desc; 7837sel.appendChild(option); 7838} 7839 7840if ( ! option_selected ) { 7841sel.selectedIndex = '-1'; 7842} 7843col.appendChild(sel); 7844break; 7845} 7846 7847row.appendChild(col); 7848} 7849return row; 7850} 7851 7852function annotation_editor_scroll_to_row(row_id) { 7853if ( is_annotation_editor_visible() ) { 7854var row_html_id = 'ae_' + _via_metadata_being_updated + '_' + row_id; 7855var row = document.getElementById(row_html_id); 7856row.scrollIntoView(false); 7857} 7858} 7859 7860function annotation_editor_highlight_row(row_id) { 7861if ( is_annotation_editor_visible() ) { 7862var row_html_id = 'ae_' + _via_metadata_being_updated + '_' + row_id; 7863var row = document.getElementById(row_html_id); 7864row.classList.add('highlight'); 7865} 7866} 7867 7868function annotation_editor_clear_row_highlight() { 7869if ( is_annotation_editor_visible() ) { 7870var ae = document.getElementById('annotation_editor'); 7871var i; 7872for ( i=0; i<ae.childNodes.length; ++i ) { 7873ae.childNodes[i].classList.remove('highlight'); 7874} 7875} 7876} 7877 7878function annotation_editor_extract_html_id_components(html_id) { 7879// html_id : attribute_name__row-id__option_id 7880var parts = html_id.split('__'); 7881var parsed_id = {}; 7882switch( parts.length ) { 7883case 3: 7884// html_id : attribute-id__row-id__option_id 7885parsed_id.attr_id = parts[0]; 7886parsed_id.row_id = parts[1]; 7887parsed_id.option_id = parts[2]; 7888break; 7889case 2: 7890// html_id : attribute-id__row-id 7891parsed_id.attr_id = parts[0]; 7892parsed_id.row_id = parts[1]; 7893break; 7894default: 7895} 7896return parsed_id; 7897} 7898 7899function _via_get_file_metadata_stat(img_index_list, attr_id) { 7900var stat = {}; 7901stat[attr_id] = {}; 7902var i, n, img_id, img_index, value; 7903n = img_index_list.length; 7904for ( i = 0; i < n; ++i ) { 7905img_index = img_index_list[i]; 7906img_id = _via_image_id_list[img_index]; 7907if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty(attr_id) ) { 7908value = _via_img_metadata[img_id].file_attributes[attr_id]; 7909if ( typeof(value) === 'object' ) { 7910// checkbox has multiple values and hence is object 7911var key; 7912for ( key in value ) { 7913if ( stat[attr_id].hasOwnProperty(key) ) { 7914stat[attr_id][key] += 1; 7915} else { 7916stat[attr_id][key] = 1; 7917} 7918} 7919} else { 7920if ( stat[attr_id].hasOwnProperty(value) ) { 7921stat[attr_id][value] += 1; 7922} else { 7923stat[attr_id][value] = 1; 7924} 7925} 7926} 7927 7928} 7929return stat; 7930} 7931 7932function _via_get_region_metadata_stat(img_index_list, attr_id) { 7933var stat = {}; 7934stat[attr_id] = {}; 7935var i, n, img_id, img_index, value; 7936var j, m; 7937n = img_index_list.length; 7938for ( i = 0; i < n; ++i ) { 7939img_index = img_index_list[i]; 7940img_id = _via_image_id_list[img_index]; 7941m = _via_img_metadata[img_id].regions.length; 7942for ( j = 0; j < m; ++j ) { 7943if ( ! image_grid_is_region_in_current_group( _via_img_metadata[img_id].regions[j].region_attributes ) ) { 7944// skip region not in current group 7945continue; 7946} 7947 7948value = _via_img_metadata[img_id].regions[j].region_attributes[attr_id]; 7949if ( typeof(value) === 'object' ) { 7950// checkbox has multiple values and hence is object 7951var key; 7952for ( key in value ) { 7953if ( stat[attr_id].hasOwnProperty(key) ) { 7954stat[attr_id][key] += 1; 7955} else { 7956stat[attr_id][key] = 1; 7957} 7958} 7959} else { 7960if ( stat[attr_id].hasOwnProperty(value) ) { 7961stat[attr_id][value] += 1; 7962} else { 7963stat[attr_id][value] = 1; 7964} 7965} 7966} 7967} 7968return stat; 7969} 7970 7971// invoked when the input entry in annotation editor receives focus 7972function annotation_editor_on_metadata_focus(p) { 7973if ( _via_annotation_editor_mode === VIA_ANNOTATION_EDITOR_MODE.ALL_REGIONS ) { 7974var pid = annotation_editor_extract_html_id_components(p.id); 7975var region_id = pid.row_id; 7976// clear existing highlights (if any) 7977toggle_all_regions_selection(false); 7978annotation_editor_clear_row_highlight(); 7979// set new selection highlights 7980set_region_select_state(region_id, true); 7981annotation_editor_scroll_to_row(region_id); 7982annotation_editor_highlight_row(region_id); 7983 7984_via_redraw_reg_canvas(); 7985} 7986} 7987 7988// invoked when the user updates annotations using the annotation editor 7989function annotation_editor_on_metadata_update(p) { 7990var pid = annotation_editor_extract_html_id_components(p.id); 7991var img_id = _via_image_id; 7992 7993var img_index_list = [ _via_image_index ]; 7994var region_id = pid.row_id; 7995if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 7996img_index_list = _via_image_grid_selected_img_index_list.slice(0); 7997region_id = -1; // this flag denotes that we want to update all regions 7998} 7999 8000if ( _via_metadata_being_updated === 'file' ) { 8001annotation_editor_update_file_metadata(img_index_list, pid.attr_id, p.value, p.checked).then( function(update_count) { 8002annotation_editor_on_metadata_update_done('file', pid.attr_id, update_count); 8003}, function(err) { 8004console.log(err) 8005show_message('Failed to update file attributes! ' + err); 8006}); 8007return; 8008} 8009 8010if ( _via_metadata_being_updated === 'region' ) { 8011annotation_editor_update_region_metadata(img_index_list, region_id, pid.attr_id, p.value, p.checked).then( function(update_count) { 8012annotation_editor_on_metadata_update_done('region', pid.attr_id, update_count); 8013}, function(err) { 8014show_message('Failed to update region attributes! '); 8015}); 8016return; 8017} 8018} 8019 8020function annotation_editor_on_metadata_update_done(type, attr_id, update_count) { 8021show_message('Updated ' + type + ' attributes of ' + update_count + ' ' + type + 's'); 8022// check if the updated attribute is one of the group variables 8023var i, n, type, attr_id; 8024n = _via_image_grid_group_var.length; 8025var clear_all_group = false; 8026for ( i = 0; i < n; ++i ) { 8027if ( _via_image_grid_group_var[i].type === type && 8028_via_image_grid_group_var[i].name === attr_id ) { 8029clear_all_group = true; 8030break; 8031} 8032} 8033_via_regions_group_color_init(); 8034_via_redraw_reg_canvas(); 8035 8036// @todo: it is wasteful to cancel the full set of groups. 8037// we should only cancel the groups that are affected by this update. 8038if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 8039if ( clear_all_group ) { 8040image_grid_show_all_project_images(); 8041} 8042} 8043} 8044 8045function annotation_editor_update_file_metadata(img_index_list, attr_id, new_value, new_checked) { 8046return new Promise( function(ok_callback, err_callback) { 8047var i, n, img_id, img_index; 8048n = img_index_list.length; 8049var update_count = 0; 8050for ( i = 0; i < n; ++i ) { 8051img_index = img_index_list[i]; 8052img_id = _via_image_id_list[img_index]; 8053 8054switch( _via_attributes['file'][attr_id].type ) { 8055case 'text': // fallback 8056case 'radio': // fallback 8057case 'dropdown': // fallback 8058case 'image': 8059_via_img_metadata[img_id].file_attributes[attr_id] = new_value; 8060update_count += 1; 8061break; 8062 8063case 'checkbox': 8064var option_id = new_value; 8065if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty(attr_id) ) { 8066if ( typeof(_via_img_metadata[img_id].file_attributes[attr_id]) !== 'object' ) { 8067var old_value = _via_img_metadata[img_id].file_attributes[attr_id]; 8068_via_img_metadata[img_id].file_attributes[attr_id] = {}; 8069if ( Object.keys(_via_attributes['file'][attr_id]['options']).includes(old_value) ) { 8070// transform existing value as checkbox option 8071_via_img_metadata[img_id].file_attributes[attr_id] = {}; 8072_via_img_metadata[img_id].file_attributes[attr_id][old_value] = true; 8073} 8074} 8075} else { 8076_via_img_metadata[img_id].file_attributes[attr_id] = {}; 8077} 8078if ( new_checked ) { 8079_via_img_metadata[img_id].file_attributes[attr_id][option_id] = true; 8080} else { 8081// false option values are not stored 8082delete _via_img_metadata[img_id].file_attributes[attr_id][option_id]; 8083} 8084update_count += 1; 8085break; 8086} 8087} 8088ok_callback(update_count); 8089}); 8090} 8091 8092function annotation_editor_update_region_metadata(img_index_list, region_id, attr_id, new_value, new_checked) { 8093return new Promise( function(ok_callback, err_callback) { 8094var i, n, img_id, img_index; 8095n = img_index_list.length; 8096var update_count = 0; 8097var region_list = []; 8098var j, m; 8099 8100if ( region_id === -1 ) { 8101// update all regions on a file (for image grid view) 8102for ( i = 0; i < n; ++i ) { 8103img_index = img_index_list[i]; 8104img_id = _via_image_id_list[img_index]; 8105 8106m = _via_img_metadata[img_id].regions.length; 8107for ( j = 0; j < m; ++j ) { 8108if ( ! image_grid_is_region_in_current_group( _via_img_metadata[img_id].regions[j].region_attributes ) ) { 8109continue; 8110} 8111 8112switch( _via_attributes['region'][attr_id].type ) { 8113case 'text': // fallback 8114case 'dropdown': // fallback 8115case 'radio': // fallback 8116case 'image': 8117_via_img_metadata[img_id].regions[j].region_attributes[attr_id] = new_value; 8118update_count += 1; 8119break; 8120case 'checkbox': 8121var option_id = new_value; 8122if ( _via_img_metadata[img_id].regions[j].region_attributes.hasOwnProperty(attr_id) ) { 8123if ( typeof(_via_img_metadata[img_id].regions[j].region_attributes[attr_id]) !== 'object' ) { 8124var old_value = _via_img_metadata[img_id].regions[j].region_attributes[attr_id]; 8125_via_img_metadata[img_id].regions[j].region_attributes[attr_id] = {} 8126if ( Object.keys(_via_attributes['region'][attr_id]['options']).includes(old_value) ) { 8127// transform existing value as checkbox option 8128_via_img_metadata[img_id].regions[j].region_attributes[attr_id][old_value] = true; 8129} 8130} 8131} else { 8132_via_img_metadata[img_id].regions[j].region_attributes[attr_id] = {}; 8133} 8134 8135if ( new_checked ) { 8136_via_img_metadata[img_id].regions[j].region_attributes[attr_id][option_id] = true; 8137} else { 8138// false option values are not stored 8139delete _via_img_metadata[img_id].regions[j].region_attributes[attr_id][option_id]; 8140} 8141update_count += 1; 8142break; 8143} 8144} 8145} 8146} else { 8147// update a single region in a file (for single image view) 8148// update all regions on a file (for image grid view) 8149for ( i = 0; i < n; ++i ) { 8150img_index = img_index_list[i]; 8151img_id = _via_image_id_list[img_index]; 8152 8153switch( _via_attributes['region'][attr_id].type ) { 8154case 'text': // fallback 8155case 'dropdown': // fallback 8156case 'radio': // fallback 8157case 'image': 8158_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id] = new_value; 8159update_count += 1; 8160break; 8161case 'checkbox': 8162var option_id = new_value; 8163 8164if ( _via_img_metadata[img_id].regions[region_id].region_attributes.hasOwnProperty(attr_id) ) { 8165if ( typeof(_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id]) !== 'object' ) { 8166var old_value = _via_img_metadata[img_id].regions[region_id].region_attributes[attr_id]; 8167_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id] = {}; 8168if ( Object.keys(_via_attributes['region'][attr_id]['options']).includes(old_value) ) { 8169// transform existing value as checkbox option 8170_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id][old_value] = true; 8171} 8172} 8173} else { 8174_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id] = {}; 8175} 8176 8177if ( new_checked ) { 8178_via_img_metadata[img_id].regions[region_id].region_attributes[attr_id][option_id] = true; 8179} else { 8180// false option values are not stored 8181delete _via_img_metadata[img_id].regions[region_id].region_attributes[attr_id][option_id]; 8182} 8183update_count += 1; 8184break; 8185} 8186} 8187} 8188ok_callback(update_count); 8189}); 8190} 8191 8192function set_region_annotations_to_default_value(rid) { 8193var attr_id; 8194for ( attr_id in _via_attributes['region'] ) { 8195var attr_type = _via_attributes['region'][attr_id].type; 8196switch( attr_type ) { 8197case 'text': 8198var default_value = _via_attributes['region'][attr_id].default_value; 8199if ( typeof(default_value) !== 'undefined' ) { 8200_via_img_metadata[_via_image_id].regions[rid].region_attributes[attr_id] = default_value; 8201} 8202break; 8203case 'image': // fallback 8204case 'dropdown': // fallback 8205case 'radio': 8206_via_img_metadata[_via_image_id].regions[rid].region_attributes[attr_id] = ''; 8207var default_options = _via_attributes['region'][attr_id].default_options; 8208if ( typeof(default_options) !== 'undefined' ) { 8209_via_img_metadata[_via_image_id].regions[rid].region_attributes[attr_id] = Object.keys(default_options)[0]; 8210} 8211break; 8212 8213case 'checkbox': 8214_via_img_metadata[_via_image_id].regions[rid].region_attributes[attr_id] = {}; 8215var default_options = _via_attributes['region'][attr_id].default_options; 8216if ( typeof(default_options) !== 'underfined' ) { 8217var option_id; 8218for ( option_id in default_options ) { 8219var default_value = default_options[option_id]; 8220if ( typeof(default_value) !== 'underfined' ) { 8221_via_img_metadata[_via_image_id].regions[rid].region_attributes[attr_id][option_id] = default_value; 8222} 8223} 8224} 8225break; 8226} 8227} 8228} 8229 8230function set_file_annotations_to_default_value(image_id) { 8231var attr_id; 8232for ( attr_id in _via_attributes['file'] ) { 8233var attr_type = _via_attributes['file'][attr_id].type; 8234switch( attr_type ) { 8235case 'text': 8236var default_value = _via_attributes['file'][attr_id].default_value; 8237_via_img_metadata[image_id].file_attributes[attr_id] = default_value; 8238break; 8239case 'image': // fallback 8240case 'dropdown': // fallback 8241case 'radio': 8242_via_img_metadata[image_id].file_attributes[attr_id] = ''; 8243var default_options = _via_attributes['file'][attr_id].default_options; 8244_via_img_metadata[image_id].file_attributes[attr_id] = Object.keys(default_options)[0]; 8245break; 8246case 'checkbox': 8247_via_img_metadata[image_id].file_attributes[attr_id] = {}; 8248var default_options = _via_attributes['file'][attr_id].default_options; 8249var option_id; 8250for ( option_id in default_options ) { 8251var default_value = default_options[option_id]; 8252_via_img_metadata[image_id].file_attributes[attr_id][option_id] = default_value; 8253} 8254break; 8255} 8256} 8257} 8258 8259function annotation_editor_increase_panel_height() { 8260var p = document.getElementById('annotation_editor_panel'); 8261if ( _via_settings.ui.annotation_editor_height < 95 ) { 8262_via_settings.ui.annotation_editor_height += VIA_ANNOTATION_EDITOR_HEIGHT_CHANGE; 8263p.style.height = _via_settings.ui.annotation_editor_height + '%'; 8264} 8265} 8266 8267function annotation_editor_decrease_panel_height() { 8268var p = document.getElementById('annotation_editor_panel'); 8269if ( _via_settings.ui.annotation_editor_height > 10 ) { 8270_via_settings.ui.annotation_editor_height -= VIA_ANNOTATION_EDITOR_HEIGHT_CHANGE; 8271p.style.height = _via_settings.ui.annotation_editor_height + '%'; 8272} 8273} 8274 8275function annotation_editor_increase_content_size() { 8276var p = document.getElementById('annotation_editor_panel'); 8277if ( _via_settings.ui.annotation_editor_fontsize < 1.6 ) { 8278_via_settings.ui.annotation_editor_fontsize += VIA_ANNOTATION_EDITOR_FONTSIZE_CHANGE; 8279p.style.fontSize = _via_settings.ui.annotation_editor_fontsize + 'rem'; 8280} 8281} 8282 8283function annotation_editor_decrease_content_size() { 8284var p = document.getElementById('annotation_editor_panel'); 8285if ( _via_settings.ui.annotation_editor_fontsize > 0.4 ) { 8286_via_settings.ui.annotation_editor_fontsize -= VIA_ANNOTATION_EDITOR_FONTSIZE_CHANGE; 8287p.style.fontSize = _via_settings.ui.annotation_editor_fontsize + 'rem'; 8288} 8289} 8290 8291// 8292// via project 8293// 8294function project_set_name(name) { 8295_via_settings.project.name = name; 8296 8297var p = document.getElementById('project_name'); 8298p.value = _via_settings.project.name; 8299} 8300 8301function project_init_default_project() { 8302if ( ! _via_settings.hasOwnProperty('project') ) { 8303_via_settings.project = {}; 8304} 8305 8306project_set_name( project_get_default_project_name() ); 8307} 8308 8309function project_on_name_update(p) { 8310project_set_name(p.value); 8311} 8312 8313function project_get_default_project_name() { 8314const now = new Date(); 8315var MONTH_SHORT_NAME = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; 8316var ts = now.getDate() + MONTH_SHORT_NAME[now.getMonth()] + now.getFullYear() + 8317'_' + now.getHours() + 'h' + now.getMinutes() + 'm'; 8318 8319var project_name = 'via_project_' + ts; 8320return project_name; 8321} 8322 8323function project_save_with_confirm() { 8324var config = {'title':'Save Project' }; 8325var input = { 'project_name': { type:'text', name:'Project Name', value:_via_settings.project.name, disabled:false, size:30 }, 8326'save_annotations':{ type:'checkbox', name:'Save region and file annotations (i.e. manual annotations)', checked:true, disabled:false}, 8327'save_attributes':{ type:'checkbox', name:'Save region and file attributes.', checked:true}, 8328'save_via_settings':{ type:'checkbox', name:'Save VIA application settings', checked:true}, 8329// 'save_base64_data':{ type:'checkbox', name:'Save base64 data of images (if present)', checked:false}, 8330// 'save_images':{type:'checkbox', 'name':'Save images <span class="warning">(WARNING: only recommended for projects containing small number of images)</span>', value:false}, 8331}; 8332 8333invoke_with_user_inputs(project_save_confirmed, input, config); 8334} 8335 8336function project_save_confirmed(input) { 8337if ( input.project_name.value !== _via_settings.project.name ) { 8338project_set_name(input.project_name.value); 8339} 8340 8341// via project 8342var _via_project = { '_via_settings': _via_settings, 8343'_via_img_metadata': _via_img_metadata, 8344'_via_attributes': _via_attributes, 8345'_via_data_format_version': '2.0.10', 8346'_via_image_id_list': _via_image_id_list 8347}; 8348 8349var filename = input.project_name.value + '.json'; 8350var data_blob = new Blob( [JSON.stringify(_via_project)], 8351{type: 'text/json;charset=utf-8'}); 8352 8353save_data_to_local_file(data_blob, filename); 8354 8355user_input_default_cancel_handler(); 8356} 8357 8358function project_open_select_project_file() { 8359if (invisible_file_input) { 8360invisible_file_input.accept = '.json'; 8361invisible_file_input.onchange = project_open; 8362invisible_file_input.removeAttribute('multiple'); 8363invisible_file_input.click(); 8364} 8365} 8366 8367function project_open(event) { 8368var selected_file = event.target.files[0]; 8369load_text_file(selected_file, project_open_parse_json_file); 8370} 8371 8372function project_open_parse_json_file(project_file_data) { 8373var d = JSON.parse(project_file_data); 8374if ( d['_via_settings'] && d['_via_img_metadata'] && d['_via_attributes'] ) { 8375// import settings 8376project_import_settings(d['_via_settings']); 8377 8378// clear existing data (if any) 8379_via_image_id_list = []; 8380_via_image_filename_list = []; 8381_via_img_count = 0; 8382_via_img_metadata = {}; 8383_via_img_fileref = {}; 8384_via_img_src = {}; 8385_via_attributes = { 'region':{}, 'file':{} }; 8386_via_buffer_remove_all(); 8387 8388// import image metadata 8389_via_img_metadata = {}; 8390for ( var img_id in d['_via_img_metadata'] ) { 8391if('filename' in d['_via_img_metadata'][img_id] && 8392'size' in d['_via_img_metadata'][img_id] && 8393'regions' in d['_via_img_metadata'][img_id] && 8394'file_attributes' in d['_via_img_metadata'][img_id]) { 8395if( !d.hasOwnProperty('_via_image_id_list') ) { 8396_via_image_id_list.push(img_id); 8397_via_image_filename_list.push( d['_via_img_metadata'][img_id].filename ); 8398} 8399 8400set_file_annotations_to_default_value(img_id); 8401_via_img_metadata[img_id] = d['_via_img_metadata'][img_id]; 8402_via_img_count += 1; 8403} else { 8404console.log('discarding malformed entry for ' + img_id + 8405': ' + JSON.stringify(d['_via_img_metadata'][img_id])); 8406} 8407} 8408 8409 8410// import image_id_list which records the order of images 8411if( d.hasOwnProperty('_via_image_id_list') ) { 8412_via_image_id_list = d['_via_image_id_list']; 8413for(var img_id_index in d['_via_image_id_list']) { 8414var img_id = d['_via_image_id_list'][img_id_index]; 8415_via_image_filename_list.push(_via_img_metadata[img_id]['filename']); 8416} 8417} 8418 8419// import attributes 8420_via_attributes = d['_via_attributes']; 8421project_parse_via_attributes_from_img_metadata(); 8422var fattr_id_list = Object.keys(_via_attributes['file']); 8423var rattr_id_list = Object.keys(_via_attributes['region']); 8424if ( rattr_id_list.length ) { 8425_via_attribute_being_updated = 'region'; 8426_via_current_attribute_id = rattr_id_list[0]; 8427} else { 8428if ( fattr_id_list.length ) { 8429_via_attribute_being_updated = 'file'; 8430_via_current_attribute_id = fattr_id_list[0]; 8431} 8432} 8433 8434if ( _via_settings.core.default_filepath !== '' ) { 8435_via_file_resolve_all_to_default_filepath(); 8436} 8437 8438show_message('Imported project [' + _via_settings['project'].name + '] with ' + _via_img_count + ' files.'); 8439 8440if ( _via_img_count > 0 ) { 8441_via_show_img(0); 8442update_img_fn_list(); 8443_via_reload_img_fn_list_table = true; 8444} 8445} else { 8446show_message('Cannot import project from a corrupt file!'); 8447} 8448} 8449 8450function project_parse_via_attributes_from_img_metadata() { 8451// parse _via_img_metadata to populate _via_attributes 8452var img_id, fa, ra; 8453 8454if ( ! _via_attributes.hasOwnProperty('file') ) { 8455_via_attributes['file'] = {}; 8456} 8457if ( ! _via_attributes.hasOwnProperty('region') ) { 8458_via_attributes['region'] = {}; 8459} 8460 8461for ( img_id in _via_img_metadata ) { 8462// file attributes 8463for ( fa in _via_img_metadata[img_id].file_attributes ) { 8464if ( ! _via_attributes['file'].hasOwnProperty(fa) ) { 8465_via_attributes['file'][fa] = {}; 8466_via_attributes['file'][fa]['type'] = 'text'; 8467} 8468} 8469// region attributes 8470var ri; 8471for ( ri = 0; ri < _via_img_metadata[img_id].regions.length; ++ri ) { 8472for ( ra in _via_img_metadata[img_id].regions[ri].region_attributes ) { 8473if ( ! _via_attributes['region'].hasOwnProperty(ra) ) { 8474_via_attributes['region'][ra] = {}; 8475_via_attributes['region'][ra]['type'] = 'text'; 8476} 8477} 8478} 8479} 8480} 8481 8482function project_import_settings(s) { 8483// @todo find a generic way to import into _via_settings 8484// only the components present in s (and not overwrite everything) 8485var k1; 8486for ( k1 in s ) { 8487if ( typeof( s[k1] ) === 'object' ) { 8488var k2; 8489for ( k2 in s[k1] ) { 8490if ( typeof( s[k1][k2] ) === 'object' ) { 8491var k3; 8492for ( k3 in s[k1][k2] ) { 8493_via_settings[k1][k2][k3] = s[k1][k2][k3]; 8494} 8495} else { 8496_via_settings[k1][k2] = s[k1][k2]; 8497} 8498} 8499} else { 8500_via_settings[k1] = s[k1]; 8501} 8502} 8503} 8504 8505function project_file_remove_with_confirm() { 8506var img_id = _via_image_id_list[_via_image_index]; 8507var filename = _via_img_metadata[img_id].filename; 8508var region_count = _via_img_metadata[img_id].regions.length; 8509 8510var config = {'title':'Remove File from Project' }; 8511var input = { 'img_index': { type:'text', name:'File Id', value:(_via_image_index+1), disabled:true, size:8 }, 8512'filename':{ type:'text', name:'Filename', value:filename, disabled:true, size:30}, 8513'region_count':{ type:'text', name:'Number of regions', disabled:true, value:region_count, size:8} 8514}; 8515 8516invoke_with_user_inputs(project_file_remove_confirmed, input, config); 8517} 8518 8519function project_file_remove_confirmed(input) { 8520var img_index = input.img_index.value - 1; 8521project_remove_file(img_index); 8522 8523if ( img_index === _via_img_count ) { 8524if ( _via_img_count === 0 ) { 8525_via_current_image_loaded = false; 8526show_home_panel(); 8527} else { 8528_via_show_img(img_index - 1); 8529} 8530} else { 8531_via_show_img(img_index); 8532} 8533_via_reload_img_fn_list_table = true; 8534update_img_fn_list(); 8535show_message('Removed file [' + input.filename.value + '] from project'); 8536user_input_default_cancel_handler(); 8537} 8538 8539 8540function project_remove_file(img_index) { 8541if ( img_index < 0 || img_index >= _via_img_count ) { 8542console.log('project_remove_file(): invalid img_index ' + img_index); 8543return; 8544} 8545var img_id = _via_image_id_list[img_index]; 8546 8547// remove img_index from all array 8548// this invalidates all image_index > img_index 8549_via_image_id_list.splice( img_index, 1 ); 8550_via_image_filename_list.splice( img_index, 1 ); 8551 8552var img_fn_list_index = _via_img_fn_list_img_index_list.indexOf(img_index); 8553if ( img_fn_list_index !== -1 ) { 8554_via_img_fn_list_img_index_list.splice( img_fn_list_index, 1 ); 8555} 8556 8557// clear all buffer 8558// @todo: it is wasteful to clear all the buffer instead of removing a single image 8559_via_buffer_remove_all(); 8560img_fn_list_clear_css_classname('buffered'); 8561 8562_via_clear_reg_canvas(); 8563delete _via_img_metadata[img_id]; 8564delete _via_img_src[img_id]; 8565delete _via_img_fileref[img_id]; 8566 8567_via_img_count -= 1; 8568} 8569 8570function project_add_new_file(filename, size, file_id) { 8571var img_id = file_id; 8572if ( typeof(img_id) === 'undefined' ) { 8573if ( typeof(size) === 'undefined' ) { 8574size = -1; 8575} 8576img_id = _via_get_image_id(filename, size); 8577} 8578 8579if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 8580_via_img_metadata[img_id] = new file_metadata(filename, size); 8581_via_image_id_list.push(img_id); 8582_via_image_filename_list.push(filename); 8583_via_img_count += 1; 8584} 8585return img_id; 8586} 8587 8588function project_file_add_local(event) { 8589var user_selected_images = event.target.files; 8590var original_image_count = _via_img_count; 8591 8592var new_img_index_list = []; 8593var discarded_file_count = 0; 8594for ( var i = 0; i < user_selected_images.length; ++i ) { 8595var filetype = user_selected_images[i].type.substr(0, 5); 8596if ( filetype === 'image' ) { 8597// check which filename in project matches the user selected file 8598var img_index = _via_image_filename_list.indexOf(user_selected_images[i].name); 8599if( img_index === -1) { 8600// a new file was added to project 8601var new_img_id = project_add_new_file(user_selected_images[i].name, 8602user_selected_images[i].size); 8603_via_img_fileref[new_img_id] = user_selected_images[i]; 8604set_file_annotations_to_default_value(new_img_id); 8605new_img_index_list.push( _via_image_id_list.indexOf(new_img_id) ); 8606} else { 8607// an existing file was resolved using browser's file selector 8608var img_id = _via_image_id_list[img_index]; 8609_via_img_fileref[img_id] = user_selected_images[i]; 8610_via_img_metadata[img_id]['size'] = user_selected_images[i].size; 8611} 8612} else { 8613discarded_file_count += 1; 8614} 8615} 8616 8617if ( _via_img_metadata ) { 8618var status_msg = 'Loaded ' + new_img_index_list.length + ' images.'; 8619if ( discarded_file_count ) { 8620status_msg += ' ( Discarded ' + discarded_file_count + ' non-image files! )'; 8621} 8622show_message(status_msg); 8623 8624if ( new_img_index_list.length ) { 8625// show first of newly added image 8626_via_show_img( new_img_index_list[0] ); 8627} else { 8628// show original image 8629_via_show_img ( _via_image_index ); 8630} 8631update_img_fn_list(); 8632} else { 8633show_message("Please upload some image files!"); 8634} 8635} 8636 8637function project_file_add_abs_path_with_input() { 8638var config = {'title':'Add File using Absolute Path' }; 8639var input = { 'absolute_path': { type:'text', name:'add one absolute path', placeholder:'/home/abhishek/image1.jpg', disabled:false, size:50 }, 8640'absolute_path_list': { type:'textarea', name:'or, add multiple paths (one path per line)', placeholder:'/home/abhishek/image1.jpg\n/home/abhishek/image2.jpg\n/home/abhishek/image3.png', disabled:false, rows:5, cols:80 } 8641}; 8642 8643invoke_with_user_inputs(project_file_add_abs_path_input_done, input, config); 8644} 8645 8646function project_file_add_abs_path_input_done(input) { 8647if ( input.absolute_path.value !== '' ) { 8648var abs_path = input.absolute_path.value.trim(); 8649var img_id = project_file_add_url(abs_path); 8650var img_index = _via_image_id_list.indexOf(img_id); 8651_via_show_img(img_index); 8652show_message('Added file at absolute path [' + abs_path + ']'); 8653update_img_fn_list(); 8654user_input_default_cancel_handler(); 8655} else { 8656if ( input.absolute_path_list.value !== '' ) { 8657var absolute_path_list_str = input.absolute_path_list.value; 8658import_files_url_from_csv(absolute_path_list_str); 8659} 8660} 8661} 8662 8663function project_file_add_url_with_input() { 8664var config = {'title':'Add File using URL' }; 8665var input = { 'url': { type:'text', name:'add one URL', placeholder:'http://www.robots.ox.ac.uk/~vgg/software/via/images/swan.jpg', disabled:false, size:50 }, 8666'url_list': { type:'textarea', name:'or, add multiple URL (one url per line)', placeholder:'http://www.example.com/image1.jpg\nhttp://www.example.com/image2.jpg\nhttp://www.example.com/image3.png', disabled:false, rows:5, cols:80 } 8667}; 8668 8669invoke_with_user_inputs(project_file_add_url_input_done, input, config); 8670} 8671 8672function project_file_add_url_input_done(input) { 8673if ( input.url.value !== '' ) { 8674var url = input.url.value.trim(); 8675var img_id = project_file_add_url(url); 8676var img_index = _via_image_id_list.indexOf(img_id); 8677show_message('Added file at url [' + url + ']'); 8678update_img_fn_list(); 8679_via_show_img(img_index); 8680user_input_default_cancel_handler(); 8681} else { 8682if ( input.url_list.value !== '' ) { 8683var url_list_str = input.url_list.value; 8684import_files_url_from_csv(url_list_str); 8685} 8686} 8687} 8688 8689function project_file_add_url(url) { 8690if ( url !== '' ) { 8691var size = -1; // convention: files added using url have size = -1 8692var img_id = _via_get_image_id(url, size); 8693 8694if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 8695img_id = project_add_new_file(url); 8696_via_img_src[img_id] = _via_img_metadata[img_id].filename; 8697set_file_annotations_to_default_value(img_id); 8698return img_id; 8699} 8700} 8701} 8702 8703function project_file_add_base64(filename, base64) { 8704var size = -1; // convention: files added using url have size = -1 8705var img_id = _via_get_image_id(filename, size); 8706 8707if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 8708img_id = project_add_new_file(filename, size); 8709_via_img_src[img_id] = base64; 8710set_file_annotations_to_default_value(img_id); 8711} 8712} 8713 8714function project_file_load_on_fail(img_index) { 8715var img_id = _via_image_id_list[img_index]; 8716_via_img_src[img_id] = ''; 8717_via_image_load_error[img_index] = true; 8718img_fn_list_ith_entry_error(img_index, true); 8719} 8720 8721function project_file_load_on_success(img_index) { 8722_via_image_load_error[img_index] = false; 8723img_fn_list_ith_entry_error(img_index, false); 8724} 8725 8726function project_settings_toggle() { 8727if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.SETTINGS ) { 8728show_single_image_view(); 8729} else { 8730project_settings_show(); 8731} 8732} 8733 8734function project_settings_show() { 8735set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.SETTINGS); 8736} 8737 8738function project_filepath_add_from_input(p, button) { 8739var new_path = document.getElementById(p).value.trim(); 8740var img_index = parseInt(button.getAttribute('value')); 8741project_filepath_add(new_path); 8742_via_show_img(img_index); 8743} 8744 8745function project_filepath_add(new_path) { 8746if ( path === '' ) { 8747return; 8748} 8749 8750if ( _via_settings.core.filepath.hasOwnProperty(new_path) ) { 8751return; 8752} else { 8753var largest_order = 0; 8754var path; 8755for ( path in _via_settings.core.filepath ) { 8756if ( _via_settings.core.filepath[path] > largest_order ) { 8757largest_order = _via_settings.core.filepath[path]; 8758} 8759} 8760_via_settings.core.filepath[new_path] = largest_order + 1; 8761 8762} 8763} 8764 8765function project_filepath_del(path) { 8766if ( _via_settings.core.filepath.hasOwnProperty(path) ) { 8767delete _via_settings.core.filepath[path]; 8768} 8769} 8770 8771function project_save_attributes() { 8772var blob_attr = {type: 'application/json;charset=utf-8'}; 8773var all_region_data_blob = new Blob( [ JSON.stringify(_via_attributes) ], blob_attr); 8774 8775save_data_to_local_file(all_region_data_blob, _via_settings.project.name + '_attributes.json'); 8776} 8777 8778function project_import_attributes_from_file(event) { 8779var selected_files = event.target.files; 8780for ( var i = 0; i < selected_files.length; ++i ) { 8781var file = selected_files[i]; 8782load_text_file(file, project_import_attributes_from_json); 8783} 8784} 8785 8786function project_import_attributes_from_json(data) { 8787try { 8788var d = JSON.parse(data); 8789var attr; 8790var fattr_count = 0; 8791var rattr_count = 0; 8792// process file attributes 8793for ( attr in d['file'] ) { 8794_via_attributes['file'][attr] = JSON.parse( JSON.stringify( d['file'][attr] ) ); 8795fattr_count += 1; 8796} 8797 8798// process region attributes 8799for ( attr in d['region'] ) { 8800_via_attributes['region'][attr] = JSON.parse( JSON.stringify( d['region'][attr] ) ); 8801rattr_count += 1; 8802} 8803 8804if ( fattr_count > 0 || rattr_count > 0 ) { 8805var fattr_id_list = Object.keys(_via_attributes['file']); 8806var rattr_id_list = Object.keys(_via_attributes['region']); 8807if ( rattr_id_list.length ) { 8808_via_attribute_being_updated = 'region'; 8809_via_current_attribute_id = rattr_id_list[0]; 8810} else { 8811if ( fattr_id_list.length ) { 8812_via_attribute_being_updated = 'file'; 8813_via_current_attribute_id = fattr_id_list[0]; 8814} 8815} 8816attribute_update_panel_set_active_button(); 8817update_attributes_update_panel(); 8818annotation_editor_update_content(); 8819} 8820show_message('Imported ' + fattr_count + ' file attributes and ' 8821+ rattr_count + ' region attributes'); 8822} catch (error) { 8823show_message('Failed to import attributes: [' + error + ']'); 8824} 8825} 8826 8827// 8828// image grid 8829// 8830function image_grid_init() { 8831var p = document.getElementById('image_grid_content'); 8832p.focus(); 8833p.addEventListener('mousedown', image_grid_mousedown_handler, false); 8834p.addEventListener('mouseup', image_grid_mouseup_handler, false); 8835p.addEventListener('dblclick', image_grid_dblclick_handler, false); 8836 8837image_grid_set_content_panel_height_fixed(); 8838 8839// select policy as defined in settings 8840var i, option; 8841var p = document.getElementById('image_grid_show_image_policy'); 8842var n = p.options.length; 8843for ( i = 0; i < n; ++i ) { 8844if ( p.options[i].value === _via_settings.ui.image_grid.show_image_policy ) { 8845p.selectedIndex = i; 8846break; 8847} 8848} 8849} 8850 8851function image_grid_update() { 8852if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 8853image_grid_set_content( _via_image_grid_img_index_list ); 8854} 8855} 8856 8857function image_grid_toggle() { 8858var p = document.getElementById('toolbar_image_grid_toggle'); 8859if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE_GRID ) { 8860image_grid_clear_all_groups(); 8861show_single_image_view(); 8862} else { 8863show_image_grid_view(); 8864} 8865} 8866 8867function image_grid_show_all_project_images() { 8868var all_img_index_list = []; 8869var i, n; 8870//n = _via_image_id_list.length; 8871n = _via_img_fn_list_img_index_list.length; 8872for ( i = 0; i < n; ++i ) { 8873all_img_index_list.push( _via_img_fn_list_img_index_list[i] ); 8874} 8875image_grid_clear_all_groups(); 8876 8877var p = document.getElementById('image_grid_toolbar_group_by_select'); 8878p.selectedIndex = 0; 8879 8880image_grid_set_content(all_img_index_list); 8881} 8882 8883function image_grid_clear_all_groups() { 8884var i, n; 8885n = _via_image_grid_group_var.length; 8886for ( i = 0; i < n; ++i ) { 8887image_grid_remove_html_group_panel( _via_image_grid_group_var[i] ); 8888image_grid_group_by_select_set_disabled( _via_image_grid_group_var[i].type, 8889_via_image_grid_group_var[i].name, 8890false); 8891} 8892_via_image_grid_group = {}; 8893_via_image_grid_group_var = []; 8894 8895} 8896 8897function image_grid_set_content(img_index_list) { 8898if ( img_index_list.length === 0 ) { 8899return; 8900} 8901if ( _via_image_grid_load_ongoing ) { 8902return; 8903} 8904 8905_via_image_grid_img_index_list = img_index_list.slice(0); 8906_via_image_grid_selected_img_index_list = img_index_list.slice(0); 8907 8908document.getElementById('image_grid_group_by_img_count').innerHTML = _via_image_grid_img_index_list.length; 8909 8910_via_image_grid_page_first_index = 0; 8911_via_image_grid_page_last_index = null; 8912_via_image_grid_stack_prev_page = []; 8913_via_image_grid_page_img_index_list = []; 8914 8915image_grid_clear_content(); 8916image_grid_set_content_panel_height_fixed(); 8917_via_image_grid_load_ongoing = true; 8918 8919var n = _via_image_grid_img_index_list.length; 8920switch ( _via_settings.ui.image_grid.show_image_policy ) { 8921case 'all': 8922_via_image_grid_page_img_index_list = _via_image_grid_img_index_list.slice(0); 8923break; 8924case 'first_mid_last': 8925if ( n < 3 ) { 8926var i; 8927for ( i = 0; i < n; ++i ) { 8928_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[i] ); 8929} 8930} else { 8931_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[0] ); 8932_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[ Math.floor(n/2) ] ); 8933_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[n-1] ); 8934} 8935break; 8936case 'even_indexed': 8937var i; 8938for ( i = 0; i < n; ++i ) { 8939if ( i % 2 !== 0 ) { // since the user views (i+1) based indexing 8940_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[i] ); 8941} 8942} 8943break; 8944case 'odd_indexed': 8945var i; 8946for ( i = 0; i < n; ++i ) { 8947if ( i % 2 === 0 ) { // since the user views (i+1) based indexing 8948_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[i] ); 8949} 8950} 8951break; 8952case 'gap5': // fallback 8953case 'gap25': // fallback 8954case 'gap50': // fallback 8955var del = parseInt( _via_settings.ui.image_grid.show_image_policy.substr( 'gap'.length ) ); 8956var i; 8957for ( i = 0; i < n; i = i + del ) { 8958_via_image_grid_page_img_index_list.push( _via_image_grid_img_index_list[i] ); 8959} 8960break; 8961} 8962 8963_via_image_grid_visible_img_index_list = []; 8964 8965image_grid_update_sel_count_html(); 8966annotation_editor_update_content(); 8967 8968image_grid_content_append_img( _via_image_grid_page_first_index ); 8969 8970show_message('[Click] toggles selection, ' + 8971'[Shift + Click] selects everything a image, ' + 8972'[Click] or [Ctrl + Click] removes selection of all subsequent or preceeding images.'); 8973} 8974 8975function image_grid_clear_content() { 8976var img_container = document.getElementById('image_grid_content_img'); 8977var img_rshape = document.getElementById('image_grid_content_rshape'); 8978img_container.innerHTML = ''; 8979img_rshape.innerHTML = ''; 8980_via_image_grid_visible_img_index_list = []; 8981} 8982 8983function image_grid_set_content_panel_height_fixed() { 8984var pc = document.getElementById('image_grid_content'); 8985var de = document.documentElement; 8986pc.style.height = (de.clientHeight - 5.5*ui_top_panel.offsetHeight) + 'px'; 8987} 8988 8989// We do not know how many images will fit in the display area. 8990// Therefore, we add images one-by-one until overflow of parent 8991// container is detected. 8992function image_grid_content_append_img( img_grid_index ) { 8993var img_index = _via_image_grid_page_img_index_list[img_grid_index]; 8994var html_img_id = image_grid_get_html_img_id(img_index); 8995var img_id = _via_image_id_list[img_index]; 8996var e = document.createElement('img'); 8997if ( _via_img_fileref[img_id] instanceof File ) { 8998var img_reader = new FileReader(); 8999img_reader.addEventListener( "error", function() { 9000//@todo 9001}, false); 9002img_reader.addEventListener( "load", function() { 9003e.src = img_reader.result; 9004}, false); 9005img_reader.readAsDataURL( _via_img_fileref[img_id] ); 9006} else { 9007e.src = _via_img_src[img_id]; 9008} 9009e.setAttribute('id', html_img_id); 9010e.setAttribute('height', _via_settings.ui.image_grid.img_height + 'px'); 9011e.setAttribute('title', '[' + (img_index+1) + '] ' + _via_img_metadata[img_id].filename); 9012 9013e.addEventListener('load', image_grid_on_img_load, false); 9014e.addEventListener('error', image_grid_on_img_error, false); 9015document.getElementById('image_grid_content_img').appendChild(e); 9016} 9017 9018function image_grid_on_img_load(e) { 9019var img = e.target; 9020var img_index = image_grid_parse_html_img_id(img.id); 9021project_file_load_on_success(img_index); 9022 9023image_grid_add_img_if_possible(img); 9024} 9025 9026function image_grid_on_img_error(e) { 9027var img = e.target; 9028var img_index = image_grid_parse_html_img_id(img.id); 9029project_file_load_on_fail(img_index); 9030image_grid_add_img_if_possible(img); 9031} 9032 9033function image_grid_add_img_if_possible(img) { 9034var img_index = image_grid_parse_html_img_id(img.id); 9035 9036var p = document.getElementById('image_grid_content_img'); 9037var img_bottom_right_corner = parseInt(img.offsetTop) + parseInt(img.height); 9038if ( p.clientHeight < img_bottom_right_corner ) { 9039// stop as addition of this image caused overflow of parent container 9040var img_container = document.getElementById('image_grid_content_img'); 9041img_container.removeChild(img); 9042 9043if ( _via_settings.ui.image_grid.show_region_shape ) { 9044image_grid_page_show_all_regions(); 9045} 9046_via_image_grid_load_ongoing = false; 9047 9048var index = _via_image_grid_page_img_index_list.indexOf(img_index); 9049_via_image_grid_page_last_index = index; 9050 9051// setup prev, next navigation 9052var info = document.getElementById('image_grid_nav'); 9053var html = []; 9054var first_index = _via_image_grid_page_first_index; 9055var last_index = _via_image_grid_page_last_index - 1; 9056html.push('<span>Showing ' + (first_index + 1) + 9057' to ' + (last_index + 1) + ' :</span>'); 9058if ( _via_image_grid_stack_prev_page.length ) { 9059html.push('<span class="text_button" onclick="image_grid_page_prev()">Prev</span>'); 9060} else { 9061html.push('<span>Prev</span>'); 9062} 9063html.push('<span class="text_button" onclick="image_grid_page_next()">Next</span'); 9064info.innerHTML = html.join(''); 9065} else { 9066// process this image and trigger addition of next image in sequence 9067var img_fn_list_index = _via_image_grid_page_img_index_list.indexOf(img_index); 9068var next_img_fn_list_index = img_fn_list_index + 1; 9069 9070_via_image_grid_visible_img_index_list.push( img_index ); 9071var is_selected = ( _via_image_grid_selected_img_index_list.indexOf(img_index) !== -1 ); 9072if ( ! is_selected ) { 9073image_grid_update_img_select(img_index, 'unselect'); 9074} 9075 9076if ( next_img_fn_list_index !== _via_image_grid_page_img_index_list.length ) { 9077if ( _via_image_grid_load_ongoing ) { 9078image_grid_content_append_img( img_fn_list_index + 1 ); 9079} else { 9080// image grid load operation was cancelled 9081_via_image_grid_page_last_index = _via_image_grid_page_first_index; // load this page again 9082 9083var info = document.getElementById('image_grid_nav'); 9084var html = []; 9085html.push('<span>Cancelled :</span>'); 9086if ( _via_image_grid_stack_prev_page.length ) { 9087html.push('<span class="text_button" onclick="image_grid_page_prev()">Prev</span>'); 9088} else { 9089html.push('<span>Prev</span>'); 9090} 9091html.push('<span class="text_button" onclick="image_grid_page_next()">Next</span'); 9092info.innerHTML = html.join(''); 9093} 9094} else { 9095// last page 9096var index = _via_image_grid_page_img_index_list.indexOf(img_index); 9097_via_image_grid_page_last_index = index; 9098 9099if ( _via_settings.ui.image_grid.show_region_shape ) { 9100image_grid_page_show_all_regions(); 9101} 9102_via_image_grid_load_ongoing = false; 9103 9104// setup prev, next navigation 9105var info = document.getElementById('image_grid_nav'); 9106var html = []; 9107var first_index = _via_image_grid_page_first_index; 9108var last_index = _via_image_grid_page_last_index; 9109html.push('<span>Showing ' + (first_index + 1) + 9110' to ' + (last_index + 1) + ' (end) </span>'); 9111if ( _via_image_grid_stack_prev_page.length ) { 9112html.push('<span class="text_button" onclick="image_grid_page_prev()">Prev</span>'); 9113} else { 9114html.push('<span>Prev</span>'); 9115} 9116html.push('<span>Next</span'); 9117 9118info.innerHTML = html.join(''); 9119} 9120} 9121} 9122 9123function image_grid_onchange_show_image_policy(p) { 9124_via_settings.ui.image_grid.show_image_policy = p.options[p.selectedIndex].value; 9125image_grid_set_content(_via_image_grid_img_index_list); 9126} 9127 9128function image_grid_page_show_all_regions() { 9129var all_promises = []; 9130if ( _via_settings.ui.image_grid.show_region_shape ) { 9131var p = document.getElementById('image_grid_content_img'); 9132var n = p.childNodes.length; 9133var i; 9134for ( i = 0; i < n; ++i ) { 9135// draw region shape into global canvas for image grid 9136var img_index = image_grid_parse_html_img_id( p.childNodes[i].id ); 9137var img_param = []; // [width, height, originalWidth, originalHeight, x, y] 9138img_param.push( parseInt(p.childNodes[i].width) ); 9139img_param.push( parseInt(p.childNodes[i].height) ); 9140img_param.push( parseInt(p.childNodes[i].naturalWidth) ); 9141img_param.push( parseInt(p.childNodes[i].naturalHeight) ); 9142img_param.push( parseInt(p.childNodes[i].offsetLeft) + parseInt(p.childNodes[i].clientLeft) ); 9143img_param.push( parseInt(p.childNodes[i].offsetTop) + parseInt(p.childNodes[i].clientTop) ); 9144var promise = image_grid_show_region_shape( img_index, img_param ); 9145all_promises.push( promise ); 9146} 9147// @todo: ensure that all promises are fulfilled 9148} 9149} 9150 9151function image_grid_is_region_in_current_group(r) { 9152var i, n; 9153n = _via_image_grid_group_var.length; 9154if ( n === 0 ) { 9155return true; 9156} 9157 9158for ( i = 0; i < n; ++i ) { 9159if ( _via_image_grid_group_var[i].type === 'region' ) { 9160var group_value = _via_image_grid_group_var[i].values[ _via_image_grid_group_var[i].current_value_index ]; 9161if ( r[_via_image_grid_group_var[i].name] != group_value ) { 9162return false; 9163} 9164} 9165} 9166return true; 9167} 9168 9169function image_grid_show_region_shape(img_index, img_param) { 9170return new Promise( function(ok_callback, err_callback) { 9171var i; 9172var img_id = _via_image_id_list[img_index]; 9173var html_img_id = image_grid_get_html_img_id(img_index); 9174var n = _via_img_metadata[img_id].regions.length; 9175var is_in_group = false; 9176for ( i = 0; i < n; ++i ) { 9177if ( ! image_grid_is_region_in_current_group( _via_img_metadata[img_id].regions[i].region_attributes ) ) { 9178// skip drawing this region which is not in current group 9179continue; 9180} 9181 9182var r = _via_img_metadata[img_id].regions[i].shape_attributes; 9183var dimg; // region coordinates in original image space 9184switch( r.name ) { 9185case VIA_REGION_SHAPE.RECT: 9186dimg = [ r['x'], r['y'], r['x']+r['width'], r['y']+r['height'] ]; 9187break; 9188case VIA_REGION_SHAPE.CIRCLE: 9189dimg = [ r['cx'], r['cy'], r['cx']+r['r'], r['cy']+r['r'] ]; 9190break; 9191case VIA_REGION_SHAPE.ELLIPSE: 9192dimg = [ r['cx'], r['cy'], r['cx']+r['rx'], r['cy']+r['ry'] ]; 9193break; 9194case VIA_REGION_SHAPE.POLYLINE: // handled by POLYGON 9195case VIA_REGION_SHAPE.POLYGON: 9196var j; 9197dimg = []; 9198for ( j = 0; j < r['all_points_x'].length; ++j ) { 9199dimg.push( r['all_points_x'][j] ); 9200dimg.push( r['all_points_y'][j] ); 9201} 9202break; 9203case VIA_REGION_SHAPE.POINT: 9204dimg = [ r['cx'], r['cy'] ]; 9205break; 9206} 9207var scale_factor = img_param[1] / img_param[3]; // new_height / original height 9208var offset_x = img_param[4]; 9209var offset_y = img_param[5]; 9210var r2 = new _via_region( r.name, i, dimg, scale_factor, offset_x, offset_y); 9211var r2_svg = r2.get_svg_element(); 9212r2_svg.setAttribute('id', image_grid_get_html_region_id(img_index, i)); 9213r2_svg.setAttribute('class', html_img_id); 9214r2_svg.setAttribute('fill', _via_settings.ui.image_grid.rshape_fill); 9215//r2_svg.setAttribute('fill-opacity', _via_settings.ui.image_grid.rshape_fill_opacity); 9216r2_svg.setAttribute('stroke', _via_settings.ui.image_grid.rshape_stroke); 9217r2_svg.setAttribute('stroke-width', _via_settings.ui.image_grid.rshape_stroke_width); 9218 9219document.getElementById('image_grid_content_rshape').appendChild(r2_svg); 9220} 9221}); 9222} 9223 9224function image_grid_image_size_increase() { 9225var new_img_height = _via_settings.ui.image_grid.img_height + VIA_IMAGE_GRID_IMG_HEIGHT_CHANGE; 9226_via_settings.ui.image_grid.img_height = new_img_height; 9227 9228_via_image_grid_page_last_index = null; 9229image_grid_update(); 9230} 9231 9232function image_grid_image_size_decrease() { 9233var new_img_height = _via_settings.ui.image_grid.img_height - VIA_IMAGE_GRID_IMG_HEIGHT_CHANGE; 9234if ( new_img_height > 1 ) { 9235_via_settings.ui.image_grid.img_height = new_img_height; 9236_via_image_grid_page_last_index = null; 9237image_grid_update(); 9238} 9239} 9240 9241function image_grid_image_size_reset() { 9242var new_img_height = _via_settings.ui.image_grid.img_height; 9243if ( new_img_height > 1 ) { 9244_via_settings.ui.image_grid.img_height = new_img_height; 9245_via_image_grid_page_last_index = null; 9246image_grid_update(); 9247} 9248} 9249 9250function image_grid_mousedown_handler(e) { 9251e.preventDefault(); 9252_via_image_grid_mousedown_img_index = image_grid_parse_html_img_id(e.target.id); 9253} 9254 9255function image_grid_mouseup_handler(e) { 9256e.preventDefault(); 9257var last_mouseup_img_index = _via_image_grid_mouseup_img_index; 9258_via_image_grid_mouseup_img_index = image_grid_parse_html_img_id(e.target.id); 9259if ( isNaN(_via_image_grid_mousedown_img_index) || 9260isNaN(_via_image_grid_mouseup_img_index)) { 9261last_mouseup_img_index = _via_image_grid_img_index_list[0]; 9262image_grid_group_select_none(); 9263return; 9264} 9265 9266var mousedown_img_arr_index = _via_image_grid_img_index_list.indexOf(_via_image_grid_mousedown_img_index); 9267var mouseup_img_arr_index = _via_image_grid_img_index_list.indexOf(_via_image_grid_mouseup_img_index); 9268 9269var start = -1; 9270var end = -1; 9271var operation = 'select'; // {'select', 'unselect', 'toggle'} 9272if ( mousedown_img_arr_index === mouseup_img_arr_index ) { 9273if ( e.shiftKey ) { 9274// select all elements until this element 9275start = _via_image_grid_img_index_list.indexOf(last_mouseup_img_index) + 1; 9276end = mouseup_img_arr_index + 1; 9277} else { 9278// toggle selection of single image 9279start = mousedown_img_arr_index; 9280end = start + 1; 9281operation = 'toggle'; 9282} 9283} else { 9284if ( mousedown_img_arr_index < mouseup_img_arr_index ) { 9285start = mousedown_img_arr_index; 9286end = mouseup_img_arr_index + 1; 9287} else { 9288start = mouseup_img_arr_index + 1; 9289end = mousedown_img_arr_index; 9290} 9291operation = 'toggle'; 9292} 9293 9294if ( start > end ) { 9295return; 9296} 9297 9298var i, img_index; 9299for ( i = start; i < end; ++i ) { 9300img_index = _via_image_grid_img_index_list[i]; 9301image_grid_update_img_select(img_index, operation); 9302} 9303image_grid_update_sel_count_html(); 9304annotation_editor_update_content(); 9305} 9306 9307function image_grid_update_sel_count_html() { 9308document.getElementById('image_grid_group_by_sel_img_count').innerHTML = _via_image_grid_selected_img_index_list.length; 9309} 9310 9311// state \in {'select', 'unselect', 'toggle'} 9312function image_grid_update_img_select(img_index, state) { 9313var html_img_id = image_grid_get_html_img_id(img_index); 9314var is_selected = ( _via_image_grid_selected_img_index_list.indexOf(img_index) !== -1 ); 9315if (state === 'toggle' ) { 9316if ( is_selected ) { 9317state = 'unselect'; 9318} else { 9319state = 'select'; 9320} 9321} 9322 9323switch(state) { 9324case 'select': 9325if ( ! is_selected ) { 9326_via_image_grid_selected_img_index_list.push(img_index); 9327} 9328if ( _via_image_grid_visible_img_index_list.indexOf(img_index) !== -1 ) { 9329document.getElementById(html_img_id).classList.remove('not_sel'); 9330} 9331break; 9332case 'unselect': 9333if ( is_selected ) { 9334var arr_index = _via_image_grid_selected_img_index_list.indexOf(img_index); 9335_via_image_grid_selected_img_index_list.splice(arr_index, 1); 9336} 9337if ( _via_image_grid_visible_img_index_list.indexOf(img_index) !== -1 ) { 9338document.getElementById(html_img_id).classList.add('not_sel'); 9339} 9340break; 9341} 9342} 9343 9344function image_grid_group_select_all() { 9345image_grid_group_set_all_selection_state('select'); 9346image_grid_update_sel_count_html(); 9347annotation_editor_update_content(); 9348show_message('Selected all images in the current group'); 9349} 9350 9351function image_grid_group_select_none() { 9352image_grid_group_set_all_selection_state('unselect'); 9353image_grid_update_sel_count_html(); 9354annotation_editor_update_content(); 9355show_message('Removed selection of all images in the current group'); 9356} 9357 9358function image_grid_group_set_all_selection_state(state) { 9359var i, img_index; 9360for ( i = 0; i < _via_image_grid_img_index_list.length; ++i ) { 9361img_index = _via_image_grid_img_index_list[i]; 9362image_grid_update_img_select(img_index, state); 9363} 9364} 9365 9366function image_grid_group_toggle_select_all() { 9367if ( _via_image_grid_selected_img_index_list.length === _via_image_grid_img_index_list.length ) { 9368image_grid_group_select_none(); 9369} else { 9370image_grid_group_select_all(); 9371} 9372} 9373 9374function image_grid_parse_html_img_id(html_img_id) { 9375var img_index = html_img_id.substr(2); 9376return parseInt(img_index); 9377} 9378 9379function image_grid_get_html_img_id(img_index) { 9380return 'im' + img_index; 9381} 9382 9383function image_grid_parse_html_region_id(html_region_id) { 9384var chunks = html_region_id.split('_'); 9385if ( chunks.length === 2 ) { 9386var img_index = parseInt(chunks[0].substr(2)); 9387var region_id = parseInt(chunks[1].substr(2)); 9388return {'img_index':img_index, 'region_id':region_id}; 9389} else { 9390console.log('image_grid_parse_html_region_id(): invalid html_region_id'); 9391return {}; 9392} 9393} 9394 9395function image_grid_get_html_region_id(img_index, region_id) { 9396return image_grid_get_html_img_id(img_index) + '_rs' + region_id; 9397} 9398 9399function image_grid_dblclick_handler(e) { 9400_via_image_index = image_grid_parse_html_img_id(e.target.id); 9401show_single_image_view(); 9402} 9403 9404function image_grid_toolbar_update_group_by_select() { 9405var p = document.getElementById('image_grid_toolbar_group_by_select'); 9406p.innerHTML = ''; 9407 9408var o = document.createElement('option'); 9409o.setAttribute('value', ''); 9410o.setAttribute('selected', 'selected'); 9411o.innerHTML = 'All Images'; 9412p.appendChild(o); 9413 9414// add file attributes 9415var fattr; 9416for ( fattr in _via_attributes['file'] ) { 9417var o = document.createElement('option'); 9418o.setAttribute('value', image_grid_toolbar_group_by_select_get_html_id('file', fattr)); 9419o.innerHTML = '[file] ' + fattr; 9420p.appendChild(o); 9421} 9422 9423// add region attributes 9424var rattr; 9425for ( rattr in _via_attributes['region'] ) { 9426var o = document.createElement('option'); 9427o.setAttribute('value', image_grid_toolbar_group_by_select_get_html_id('region', rattr)); 9428o.innerHTML = '[region] ' + rattr; 9429p.appendChild(o); 9430} 9431} 9432 9433function image_grid_toolbar_group_by_select_get_html_id(type, name) { 9434if ( type === 'file' ) { 9435return 'f_' + name; 9436} 9437if ( type === 'region' ) { 9438return 'r_' + name; 9439} 9440} 9441 9442function image_grid_toolbar_group_by_select_parse_html_id(id) { 9443if ( id.startsWith('f_') ) { 9444return { 'attr_type':'file', 'attr_name':id.substr(2) }; 9445} 9446if ( id.startsWith('r_') ) { 9447return { 'attr_type':'region', 'attr_name':id.substr(2) }; 9448} 9449} 9450 9451function image_grid_toolbar_onchange_group_by_select(p) { 9452if ( p.options[p.selectedIndex].value === '' ) { 9453image_grid_show_all_project_images(); 9454return; 9455} 9456 9457var v = image_grid_toolbar_group_by_select_parse_html_id( p.options[p.selectedIndex].value ); 9458var attr_type = v.attr_type; 9459var attr_name = v.attr_name; 9460image_grid_group_by(attr_type, attr_name); 9461 9462image_grid_group_by_select_set_disabled(attr_type, attr_name, true); 9463p.blur(); // to avoid adding new groups using keyboard keys as dropdown is still in focus 9464} 9465 9466function image_grid_remove_html_group_panel(d) { 9467var p = document.getElementById('group_toolbar_' + d.group_index); 9468document.getElementById('image_grid_group_panel').removeChild(p); 9469} 9470 9471function image_grid_add_html_group_panel(d) { 9472var p = document.createElement('div'); 9473p.classList.add('image_grid_group_toolbar'); 9474p.setAttribute('id', 'group_toolbar_' + d.group_index); 9475 9476var del = document.createElement('span'); 9477del.classList.add('text_button'); 9478del.setAttribute('onclick', 'image_grid_remove_group_by(this)'); 9479del.innerHTML = '×'; 9480p.appendChild(del); 9481 9482var prev = document.createElement('button'); 9483prev.innerHTML = '<'; 9484prev.setAttribute('value', d.group_index); 9485prev.setAttribute('onclick', 'image_grid_group_prev(this)'); 9486p.appendChild(prev); 9487 9488var sel = document.createElement('select'); 9489sel.setAttribute('id', image_grid_group_select_get_html_id(d.group_index)); 9490sel.setAttribute('onchange', 'image_grid_group_value_onchange(this)'); 9491var i, value; 9492var n = d.values.length; 9493var current_value = d.values[ d.current_value_index ]; 9494for ( i = 0; i < n; ++i ) { 9495value = d.values[i]; 9496var o = document.createElement('option'); 9497o.setAttribute('value', value); 9498o.innerHTML = (i+1) + '/' + n + ': ' + d.name + ' = ' + value; 9499if ( value === current_value ) { 9500o.setAttribute('selected', 'selected'); 9501} 9502 9503sel.appendChild(o); 9504} 9505p.appendChild(sel); 9506 9507var next = document.createElement('button'); 9508next.innerHTML = '>'; 9509next.setAttribute('value', d.group_index); 9510next.setAttribute('onclick', 'image_grid_group_next(this)'); 9511p.appendChild(next); 9512 9513document.getElementById('image_grid_group_panel').appendChild(p); 9514} 9515 9516function image_grid_group_panel_set_selected_value(group_index) { 9517var sel = document.getElementById(image_grid_group_select_get_html_id(group_index)); 9518sel.selectedIndex = _via_image_grid_group_var[group_index].current_value_index; 9519} 9520 9521function image_grid_group_panel_set_options(group_index) { 9522var sel = document.getElementById(image_grid_group_select_get_html_id(group_index)); 9523sel.innerHTML = ''; 9524 9525var i, value; 9526var n = _via_image_grid_group_var[group_index].values.length; 9527var name = _via_image_grid_group_var[group_index].name; 9528var current_value = _via_image_grid_group_var[group_index].values[ _via_image_grid_group_var[group_index].current_value_index ] 9529for ( i = 0; i < n; ++i ) { 9530value = _via_image_grid_group_var[group_index].values[i]; 9531var o = document.createElement('option'); 9532o.setAttribute('value', value); 9533o.innerHTML = (i+1) + '/' + n + ': ' + name + ' = ' + value; 9534if ( value === current_value ) { 9535o.setAttribute('selected', 'selected'); 9536} 9537sel.appendChild(o); 9538} 9539} 9540 9541function image_grid_group_select_get_html_id(group_index) { 9542return 'gi_' + group_index; 9543} 9544 9545function image_grid_group_select_parse_html_id(id) { 9546return parseInt(id.substr(3)); 9547} 9548 9549function image_grid_group_by_select_set_disabled(type, name, is_disabled) { 9550var p = document.getElementById('image_grid_toolbar_group_by_select'); 9551var sel_option_value = image_grid_toolbar_group_by_select_get_html_id(type, name); 9552 9553var n = p.options.length; 9554var option_value; 9555var i; 9556for ( i = 0; i < n; ++i ) { 9557if ( sel_option_value === p.options[i].value ) { 9558if ( is_disabled ) { 9559p.options[i].setAttribute('disabled', 'disabled'); 9560} else { 9561p.options[i].removeAttribute('disabled'); 9562} 9563break; 9564} 9565} 9566} 9567 9568function image_grid_remove_group_by(p) { 9569var prefix = 'group_toolbar_'; 9570var group_index = parseInt( p.parentNode.id.substr( prefix.length ) ); 9571 9572if ( group_index === 0 ) { 9573image_grid_show_all_project_images(); 9574} else { 9575// merge all groups that are child of group_index 9576image_grid_group_by_merge(_via_image_grid_group, 0, group_index); 9577 9578var n = _via_image_grid_group_var.length; 9579var p = document.getElementById('image_grid_group_panel'); 9580var group_panel_id; 9581var i; 9582for ( i = group_index; i < n; ++i ) { 9583image_grid_remove_html_group_panel( _via_image_grid_group_var[i] ); 9584image_grid_group_by_select_set_disabled( _via_image_grid_group_var[i].type, 9585_via_image_grid_group_var[i].name, 9586false); 9587} 9588_via_image_grid_group_var.splice(group_index); 9589 9590image_grid_set_content_to_current_group(); 9591} 9592} 9593 9594function image_grid_group_by(type, name) { 9595if ( Object.keys(_via_image_grid_group).length === 0 ) { 9596// first group 9597var img_index_array = []; 9598var n = _via_img_fn_list_img_index_list.length; 9599var i; 9600for ( i = 0; i < n; ++i ) { 9601img_index_array.push( _via_img_fn_list_img_index_list[i] ); 9602} 9603 9604_via_image_grid_group = image_grid_split_array_to_group(img_index_array, type, name); 9605var new_group_values = Object.keys(_via_image_grid_group); 9606_via_image_grid_group_var = []; 9607_via_image_grid_group_var.push( { 'type':type, 'name':name, 'current_value_index':0, 'values':new_group_values, 'group_index':0 } ); 9608 9609image_grid_add_html_group_panel(_via_image_grid_group_var[0]); 9610} else { 9611image_grid_group_split_all_arrays( _via_image_grid_group, type, name ); 9612 9613var i, n, value; 9614var current_group_value = _via_image_grid_group; 9615n = _via_image_grid_group_var.length; 9616 9617for ( i = 0; i < n; ++i ) { 9618value = _via_image_grid_group_var[i].values[ _via_image_grid_group_var[i].current_value_index ]; 9619current_group_value = current_group_value[ value ]; 9620} 9621var new_group_values = Object.keys(current_group_value); 9622var group_var_index = _via_image_grid_group_var.length; 9623_via_image_grid_group_var.push( { 'type':type, 'name':name, 'current_value_index':0, 'values':new_group_values, 'group_index':group_var_index } ); 9624image_grid_add_html_group_panel( _via_image_grid_group_var[group_var_index] ); 9625} 9626 9627image_grid_set_content_to_current_group(); 9628} 9629 9630function image_grid_group_by_merge(group, current_level, target_level) { 9631var child_value; 9632var group_data = []; 9633if ( current_level === target_level ) { 9634return image_grid_group_by_collapse(group); 9635} else { 9636for ( child_value in group ) { 9637group[child_value] = image_grid_group_by_merge(group[child_value], current_level + 1, target_level); 9638} 9639} 9640} 9641 9642function image_grid_group_by_collapse(group) { 9643var child_value; 9644var child_collapsed_value; 9645var group_data = []; 9646for ( child_value in group ) { 9647if ( Array.isArray(group[child_value]) ) { 9648group_data = group_data.concat(group[child_value]); 9649} else { 9650group_data = group_data.concat(image_grid_group_by_collapse(group[child_value])); 9651} 9652} 9653return group_data; 9654} 9655 9656// recursively collapse all arrays to list 9657function image_grid_group_split_all_arrays(group, type, name) { 9658if ( Array.isArray(group) ) { 9659return image_grid_split_array_to_group(group, type, name); 9660} else { 9661var group_value; 9662for ( group_value in group ) { 9663if ( Array.isArray( group[group_value] ) ) { 9664group[group_value] = image_grid_split_array_to_group(group[group_value], type, name); 9665} else { 9666image_grid_group_split_all_arrays(group[group_value], type, name); 9667} 9668} 9669} 9670} 9671 9672function image_grid_split_array_to_group(img_index_array, attr_type, attr_name) { 9673var grp = {}; 9674var img_index, img_id, i; 9675var n = img_index_array.length; 9676var attr_value; 9677 9678switch(attr_type) { 9679case 'file': 9680for ( i = 0; i < n; ++i ) { 9681img_index = img_index_array[i]; 9682img_id = _via_image_id_list[img_index]; 9683if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty(attr_name) ) { 9684attr_value = _via_img_metadata[img_id].file_attributes[attr_name]; 9685 9686if ( ! grp.hasOwnProperty(attr_value) ) { 9687grp[attr_value] = []; 9688} 9689grp[attr_value].push(img_index); 9690} 9691} 9692break; 9693case 'region': 9694var j; 9695var region_count; 9696for ( i = 0; i < n; ++i ) { 9697img_index = img_index_array[i]; 9698img_id = _via_image_id_list[img_index]; 9699region_count = _via_img_metadata[img_id].regions.length; 9700for ( j = 0; j < region_count; ++j ) { 9701if ( _via_img_metadata[img_id].regions[j].region_attributes.hasOwnProperty(attr_name) ) { 9702attr_value = _via_img_metadata[img_id].regions[j].region_attributes[attr_name]; 9703 9704if ( ! grp.hasOwnProperty(attr_value) ) { 9705grp[attr_value] = []; 9706} 9707if ( grp[attr_value].includes(img_index) ) { 9708continue; 9709} else { 9710grp[attr_value].push(img_index); 9711} 9712} 9713} 9714} 9715break; 9716} 9717return grp; 9718} 9719 9720function image_grid_group_next(p) { 9721var group_index = parseInt( p.value ); 9722var group_value_list = _via_image_grid_group_var[group_index].values; 9723var n = group_value_list.length; 9724var current_index = _via_image_grid_group_var[group_index].current_value_index; 9725var next_index = current_index + 1; 9726if ( next_index >= n ) { 9727if ( group_index === 0 ) { 9728next_index = next_index - n; 9729image_grid_jump_to_group(group_index, next_index); 9730} else { 9731// next of parent group 9732var parent_group_index = group_index - 1; 9733var parent_current_val_index = _via_image_grid_group_var[parent_group_index].current_value_index; 9734var parent_next_val_index = parent_current_val_index + 1; 9735while ( parent_group_index !== 0 ) { 9736if ( parent_next_val_index >= _via_image_grid_group_var[parent_group_index].values.length ) { 9737parent_group_index = group_index - 1; 9738parent_current_val_index = _via_image_grid_group_var[parent_group_index].current_value_index; 9739parent_next_val_index = parent_current_val_index + 1; 9740} else { 9741break; 9742} 9743} 9744 9745if ( parent_next_val_index >= _via_image_grid_group_var[parent_group_index].values.length ) { 9746parent_next_val_index = 0; 9747} 9748image_grid_jump_to_group(parent_group_index, parent_next_val_index); 9749} 9750} else { 9751image_grid_jump_to_group(group_index, next_index); 9752} 9753image_grid_set_content_to_current_group(); 9754} 9755 9756function image_grid_group_prev(p) { 9757var group_index = parseInt( p.value ); 9758var group_value_list = _via_image_grid_group_var[group_index].values; 9759var n = group_value_list.length; 9760var current_index = _via_image_grid_group_var[group_index].current_value_index; 9761var prev_index = current_index - 1; 9762if ( prev_index < 0 ) { 9763if ( group_index === 0 ) { 9764prev_index = n + prev_index; 9765image_grid_jump_to_group(group_index, prev_index); 9766} else { 9767// prev of parent group 9768var parent_group_index = group_index - 1; 9769var parent_current_val_index = _via_image_grid_group_var[parent_group_index].current_value_index; 9770var parent_prev_val_index = parent_current_val_index - 1; 9771while ( parent_group_index !== 0 ) { 9772if ( parent_prev_val_index < 0 ) { 9773parent_group_index = group_index - 1; 9774parent_current_val_index = _via_image_grid_group_var[parent_group_index].current_value_index; 9775parent_prev_val_index = parent_current_val_index - 1; 9776} else { 9777break; 9778} 9779} 9780 9781if ( parent_prev_val_index < 0 ) { 9782parent_prev_val_index = _via_image_grid_group_var[parent_group_index].values.length - 1; 9783} 9784image_grid_jump_to_group(parent_group_index, parent_prev_val_index); 9785} 9786} else { 9787image_grid_jump_to_group(group_index, prev_index); 9788} 9789image_grid_set_content_to_current_group(); 9790} 9791 9792 9793function image_grid_group_value_onchange(p) { 9794var group_index = image_grid_group_select_parse_html_id(p.id); 9795image_grid_jump_to_group(group_index, p.selectedIndex); 9796image_grid_set_content_to_current_group(); 9797} 9798 9799function image_grid_jump_to_group(group_index, value_index) { 9800var n = _via_image_grid_group_var[group_index].values.length; 9801if ( value_index >=n || value_index < 0 ) { 9802return; 9803} 9804 9805_via_image_grid_group_var[group_index].current_value_index = value_index; 9806image_grid_group_panel_set_selected_value( group_index ); 9807 9808// reset the value of lower groups 9809var i, value; 9810if ( group_index + 1 < _via_image_grid_group_var.length ) { 9811var e = _via_image_grid_group; 9812for ( i = 0; i <= group_index; ++i ) { 9813value = _via_image_grid_group_var[i].values[ _via_image_grid_group_var[i].current_value_index ]; 9814e = e[ value ]; 9815} 9816 9817for ( i = group_index + 1; i < _via_image_grid_group_var.length; ++i ) { 9818_via_image_grid_group_var[i].values = Object.keys(e); 9819if ( _via_image_grid_group_var[i].values.length === 0 ) { 9820_via_image_grid_group_var[i].current_value_index = -1; 9821_via_image_grid_group_var.splice(i); 9822image_grid_group_panel_set_options(i); 9823break; 9824} else { 9825_via_image_grid_group_var[i].current_value_index = 0; 9826value = _via_image_grid_group_var[i].values[0] 9827e = e[value]; 9828image_grid_group_panel_set_options(i); 9829} 9830} 9831} 9832} 9833 9834function image_grid_set_content_to_current_group() { 9835var n = _via_image_grid_group_var.length; 9836 9837if ( n === 0 ) { 9838image_grid_show_all_project_images(); 9839} else { 9840var group_img_index_list = []; 9841var img_index_list = _via_image_grid_group; 9842var i, n, value, current_value_index; 9843for ( i = 0; i < n; ++i ) { 9844value = _via_image_grid_group_var[i].values[ _via_image_grid_group_var[i].current_value_index ]; 9845img_index_list = img_index_list[ value ]; 9846} 9847 9848if ( Array.isArray(img_index_list) ) { 9849image_grid_set_content(img_index_list); 9850} else { 9851console.log('Error: image_grid_set_content_to_current_group(): expected array while got ' + typeof(img_index_list)); 9852} 9853} 9854} 9855 9856function image_grid_page_next() { 9857_via_image_grid_stack_prev_page.push(_via_image_grid_page_first_index); 9858_via_image_grid_page_first_index = _via_image_grid_page_last_index; 9859 9860image_grid_clear_content(); 9861_via_image_grid_load_ongoing = true; 9862image_grid_page_nav_show_cancel(); 9863image_grid_content_append_img( _via_image_grid_page_first_index ); 9864} 9865 9866function image_grid_page_prev() { 9867_via_image_grid_page_first_index = _via_image_grid_stack_prev_page.pop(); 9868_via_image_grid_page_last_index = -1; 9869 9870image_grid_clear_content(); 9871_via_image_grid_load_ongoing = true; 9872image_grid_page_nav_show_cancel(); 9873image_grid_content_append_img( _via_image_grid_page_first_index ); 9874} 9875 9876function image_grid_page_nav_show_cancel() { 9877var info = document.getElementById('image_grid_nav'); 9878var html = []; 9879html.push('<span>Loading images ... </span>'); 9880html.push('<span class="text_button" onclick="image_grid_cancel_load_ongoing()">Cancel</span>'); 9881info.innerHTML = html.join(''); 9882} 9883 9884function image_grid_cancel_load_ongoing() { 9885_via_image_grid_load_ongoing = false; 9886} 9887 9888 9889// everything to do with image zooming 9890function image_zoom_init() { 9891 9892} 9893 9894// 9895// hooks for sub-modules 9896// implemented by sub-modules 9897// 9898//function _via_hook_next_image() {} 9899//function _via_hook_prev_image() {} 9900 9901 9902//////////////////////////////////////////////////////////////////////////////// 9903// 9904// Code borrowed from via2 branch 9905// - in future, the <canvas> based reigon shape drawing will be replaced by <svg> 9906// because svg allows independent manipulation of individual regions without 9907// requiring to clear the canvas every time some region is updated. 9908// 9909//////////////////////////////////////////////////////////////////////////////// 9910 9911//////////////////////////////////////////////////////////////////////////////// 9912// 9913// @file _via_region.js 9914// @description Implementation of region shapes like rectangle, circle, etc. 9915// @author Abhishek Dutta <adutta@robots.ox.ac.uk> 9916// @date 17 June 2017 9917// 9918//////////////////////////////////////////////////////////////////////////////// 9919 9920function _via_region( shape, id, data_img_space, view_scale_factor, view_offset_x, view_offset_y) { 9921// Note the following terminology: 9922// view space : 9923// - corresponds to the x-y plane on which the scaled version of original image is shown to the user 9924// - all the region query operations like is_inside(), is_on_edge(), etc are performed in view space 9925// - all svg draw operations like get_svg() are also in view space 9926// 9927// image space : 9928// - corresponds to the x-y plane which corresponds to the spatial space of the original image 9929// - region save, export, git push operations are performed in image space 9930// - to avoid any rounding issues (caused by floating scale factor), 9931// * user drawn regions in view space is first converted to image space 9932// * this region in image space is now used to initialize region in view space 9933// 9934// The two spaces are related by _via_model.now.tform.scale which is computed by the method 9935// _via_ctrl.compute_view_panel_to_nowfile_tform() 9936// and applied as follows: 9937// x coordinate in image space = scale_factor * x coordinate in view space 9938// 9939// shape : {rect, circle, ellipse, line, polyline, polygon, point} 9940// id : unique region-id 9941// d[] : (in view space) data whose meaning depend on region shape as follows: 9942// rect : d[x1,y1,x2,y2] or d[corner1_x, corner1_y, corner2_x, corner2_y] 9943// circle : d[x1,y1,x2,y2] or d[center_x, center_y, circumference_x, circumference_y] 9944// ellipse : d[x1,y1,x2,y2,transform] 9945// line : d[x1,y1,x2,y2] 9946// polyline : d[x1,y1,...,xn,yn] 9947// polygon : d[x1,y1,...,xn,yn] 9948// point : d[cx,cy] 9949// scale_factor : for conversion from view space to image space 9950// 9951// Note: no svg data are stored with prefix "_". For example: _scale_factor, _x2 9952this.shape = shape; 9953this.id = id; 9954this.scale_factor = view_scale_factor; 9955this.offset_x = view_offset_x; 9956this.offset_y = view_offset_y; 9957this.recompute_svg = false; 9958this.attributes = {}; 9959 9960var n = data_img_space.length; 9961var i; 9962this.dview = new Array(n); 9963this.dimg = new Array(n); 9964 9965if ( n !== 0 ) { 9966// IMPORTANT: 9967// to avoid any rounding issues (caused by floating scale factor), we stick to 9968// the principal that image space coordinates are the ground truth for every region. 9969// Hence, we proceed as: 9970// * user drawn regions in view space is first converted to image space 9971// * this region in image space is now used to initialize region in view space 9972for ( i = 0; i < n; i++ ) { 9973this.dimg[i] = data_img_space[i]; 9974 9975var offset = this.offset_x; 9976if ( i % 2 !== 0 ) { 9977// y coordinate 9978offset = this.offset_y; 9979} 9980this.dview[i] = Math.round( this.dimg[i] * this.scale_factor ) + offset; 9981} 9982} 9983 9984// set svg attributes for each shape 9985switch( this.shape ) { 9986case "rect": 9987_via_region_rect.call( this ); 9988this.svg_attributes = ['x', 'y', 'width', 'height']; 9989break; 9990case "circle": 9991_via_region_circle.call( this ); 9992this.svg_attributes = ['cx', 'cy', 'r']; 9993break; 9994case "ellipse": 9995_via_region_ellipse.call( this ); 9996this.svg_attributes = ['cx', 'cy', 'rx', 'ry','transform']; 9997break; 9998case "line": 9999_via_region_line.call( this ); 10000this.svg_attributes = ['x1', 'y1', 'x2', 'y2']; 10001break; 10002case "polyline": 10003_via_region_polyline.call( this ); 10004this.svg_attributes = ['points']; 10005break; 10006case "polygon": 10007_via_region_polygon.call( this ); 10008this.svg_attributes = ['points']; 10009break; 10010case "point": 10011_via_region_point.call( this ); 10012// point is a special circle with minimal radius required for visualization 10013this.shape = 'circle'; 10014this.svg_attributes = ['cx', 'cy', 'r']; 10015break; 10016} 10017 10018this.initialize(); 10019} 10020 10021 10022_via_region.prototype.prepare_svg_element = function() { 10023var _VIA_SVG_NS = "http://www.w3.org/2000/svg"; 10024this.svg_element = document.createElementNS(_VIA_SVG_NS, this.shape); 10025this.svg_string = '<' + this.shape; 10026this.svg_element.setAttributeNS(null, 'id', this.id); 10027 10028var n = this.svg_attributes.length; 10029for ( var i = 0; i < n; i++ ) { 10030this.svg_element.setAttributeNS(null, this.svg_attributes[i], this[this.svg_attributes[i]]); 10031this.svg_string += ' ' + this.svg_attributes[i] + '="' + this[this.svg_attributes[i]] + '"'; 10032} 10033this.svg_string += '/>'; 10034} 10035 10036_via_region.prototype.get_svg_element = function() { 10037if ( this.recompute_svg ) { 10038this.prepare_svg_element(); 10039this.recompute_svg = false; 10040} 10041return this.svg_element; 10042} 10043 10044_via_region.prototype.get_svg_string = function() { 10045if ( this.recompute_svg ) { 10046this.prepare_svg_element(); 10047this.recompute_svg = false; 10048} 10049return this.svg_string; 10050} 10051 10052/// 10053/// Region shape : rectangle 10054/// 10055function _via_region_rect() { 10056this.is_inside = _via_region_rect.prototype.is_inside; 10057this.is_on_edge = _via_region_rect.prototype.is_on_edge; 10058this.move = _via_region_rect.prototype.move; 10059this.resize = _via_region_rect.prototype.resize; 10060this.initialize = _via_region_rect.prototype.initialize; 10061this.dist_to_nearest_edge = _via_region_rect.prototype.dist_to_nearest_edge; 10062} 10063 10064_via_region_rect.prototype.initialize = function() { 10065// ensure that this.(x,y) corresponds to top-left corner of rectangle 10066// Note: this.(x2,y2) is defined for convenience in calculations 10067if ( this.dview[0] < this.dview[2] ) { 10068this.x = this.dview[0]; 10069this.x2 = this.dview[2]; 10070} else { 10071this.x = this.dview[2]; 10072this.x2 = this.dview[0]; 10073} 10074if ( this.dview[1] < this.dview[3] ) { 10075this.y = this.dview[1]; 10076this.y2 = this.dview[3]; 10077} else { 10078this.y = this.dview[3]; 10079this.y2 = this.dview[1]; 10080} 10081this.width = this.x2 - this.x; 10082this.height = this.y2 - this.y; 10083this.recompute_svg = true; 10084} 10085 10086/// 10087/// Region shape : circle 10088/// 10089function _via_region_circle() { 10090this.is_inside = _via_region_circle.prototype.is_inside; 10091this.is_on_edge = _via_region_circle.prototype.is_on_edge; 10092this.move = _via_region_circle.prototype.move; 10093this.resize = _via_region_circle.prototype.resize; 10094this.initialize = _via_region_circle.prototype.initialize; 10095this.dist_to_nearest_edge = _via_region_circle.prototype.dist_to_nearest_edge; 10096} 10097 10098_via_region_circle.prototype.initialize = function() { 10099this.cx = this.dview[0]; 10100this.cy = this.dview[1]; 10101var dx = this.dview[2] - this.dview[0]; 10102var dy = this.dview[3] - this.dview[1]; 10103this.r = Math.round( Math.sqrt(dx * dx + dy * dy) ); 10104this.r2 = this.r * this.r; 10105this.recompute_svg = true; 10106} 10107 10108 10109/// 10110/// Region shape : ellipse 10111/// 10112function _via_region_ellipse() { 10113this.is_inside = _via_region_ellipse.prototype.is_inside; 10114this.is_on_edge = _via_region_ellipse.prototype.is_on_edge; 10115this.move = _via_region_ellipse.prototype.move; 10116this.resize = _via_region_ellipse.prototype.resize; 10117this.initialize = _via_region_ellipse.prototype.initialize; 10118this.dist_to_nearest_edge = _via_region_ellipse.prototype.dist_to_nearest_edge; 10119} 10120 10121_via_region_ellipse.prototype.initialize = function() { 10122this.cx = this.dview[0]; 10123this.cy = this.dview[1]; 10124this.rx = Math.abs(this.dview[2] - this.dview[0]); 10125this.ry = Math.abs(this.dview[3] - this.dview[1]); 10126 10127this.inv_rx2 = 1 / (this.rx * this.rx); 10128this.inv_ry2 = 1 / (this.ry * this.ry); 10129 10130this.recompute_svg = true; 10131} 10132 10133 10134 10135/// 10136/// Region shape : line 10137/// 10138function _via_region_line() { 10139this.is_inside = _via_region_line.prototype.is_inside; 10140this.is_on_edge = _via_region_line.prototype.is_on_edge; 10141this.move = _via_region_line.prototype.move; 10142this.resize = _via_region_line.prototype.resize; 10143this.initialize = _via_region_line.prototype.initialize; 10144this.dist_to_nearest_edge = _via_region_line.prototype.dist_to_nearest_edge; 10145} 10146 10147_via_region_line.prototype.initialize = function() { 10148this.x1 = this.dview[0]; 10149this.y1 = this.dview[1]; 10150this.x2 = this.dview[2]; 10151this.y2 = this.dview[3]; 10152this.dx = this.x1 - this.x2; 10153this.dy = this.y1 - this.y2; 10154this.mconst = (this.x1 * this.y2) - (this.x2 * this.y1); 10155 10156this.recompute_svg = true; 10157} 10158 10159 10160/// 10161/// Region shape : polyline 10162/// 10163function _via_region_polyline() { 10164this.is_inside = _via_region_polyline.prototype.is_inside; 10165this.is_on_edge = _via_region_polyline.prototype.is_on_edge; 10166this.move = _via_region_polyline.prototype.move; 10167this.resize = _via_region_polyline.prototype.resize; 10168this.initialize = _via_region_polyline.prototype.initialize; 10169this.dist_to_nearest_edge = _via_region_polyline.prototype.dist_to_nearest_edge; 10170} 10171 10172_via_region_polyline.prototype.initialize = function() { 10173var n = this.dview.length; 10174var points = new Array(n/2); 10175var points_index = 0; 10176for ( var i = 0; i < n; i += 2 ) { 10177points[points_index] = ( this.dview[i] + ' ' + this.dview[i+1] ); 10178points_index++; 10179} 10180this.points = points.join(','); 10181this.recompute_svg = true; 10182} 10183 10184 10185/// 10186/// Region shape : polygon 10187/// 10188function _via_region_polygon() { 10189this.is_inside = _via_region_polygon.prototype.is_inside; 10190this.is_on_edge = _via_region_polygon.prototype.is_on_edge; 10191this.move = _via_region_polygon.prototype.move; 10192this.resize = _via_region_polygon.prototype.resize; 10193this.initialize = _via_region_polygon.prototype.initialize; 10194this.dist_to_nearest_edge = _via_region_polygon.prototype.dist_to_nearest_edge; 10195} 10196 10197_via_region_polygon.prototype.initialize = function() { 10198var n = this.dview.length; 10199var points = new Array(n/2); 10200var points_index = 0; 10201for ( var i = 0; i < n; i += 2 ) { 10202points[points_index] = ( this.dview[i] + ' ' + this.dview[i+1] ); 10203points_index++; 10204} 10205this.points = points.join(','); 10206this.recompute_svg = true; 10207} 10208 10209 10210/// 10211/// Region shape : point 10212/// 10213function _via_region_point() { 10214this.is_inside = _via_region_point.prototype.is_inside; 10215this.is_on_edge = _via_region_point.prototype.is_on_edge; 10216this.move = _via_region_point.prototype.move; 10217this.resize = _via_region_point.prototype.resize 10218this.initialize = _via_region_point.prototype.initialize; 10219this.dist_to_nearest_edge = _via_region_point.prototype.dist_to_nearest_edge; 10220} 10221 10222_via_region_point.prototype.initialize = function() { 10223this.cx = this.dview[0]; 10224this.cy = this.dview[1]; 10225this.r = 2; 10226this.r2 = this.r * this.r; 10227this.recompute_svg = true; 10228} 10229 10230// 10231// image buffering 10232// 10233 10234function _via_cancel_current_image_loading() { 10235var panel = document.getElementById('project_panel_title'); 10236panel.innerHTML = 'Project'; 10237_via_is_loading_current_image = false; 10238} 10239 10240function _via_show_img(img_index) { 10241if ( _via_is_loading_current_image ) { 10242return; 10243} 10244 10245var img_id = _via_image_id_list[img_index]; 10246 10247if ( ! _via_img_metadata.hasOwnProperty(img_id) ) { 10248console.log('_via_show_img(): [' + img_index + '] ' + img_id + ' does not exist!') 10249show_message('The requested image does not exist!') 10250return; 10251} 10252 10253// file_resolve() is not necessary for files selected using browser's file selector 10254if ( typeof(_via_img_fileref[img_id]) === 'undefined' || ! _via_img_fileref[img_id] instanceof File ) { 10255// try preload from local file or url 10256if ( typeof(_via_img_src[img_id]) === 'undefined' || _via_img_src[img_id] === '' ) { 10257if ( is_url( _via_img_metadata[img_id].filename ) ) { 10258_via_img_src[img_id] = _via_img_metadata[img_id].filename; 10259_via_show_img(img_index); 10260return; 10261} else { 10262var search_path_list = _via_file_get_search_path_list(); 10263if ( search_path_list.length === 0 ) { 10264search_path_list.push(''); // search using just the filename 10265} 10266 10267_via_file_resolve(img_index, search_path_list).then( function(ok_file_index) { 10268_via_show_img(img_index); 10269}, function(err_file_index) { 10270show_page_404(img_index); 10271}); 10272return; 10273} 10274} 10275} 10276 10277if ( _via_buffer_img_index_list.includes(img_index) ) { 10278_via_current_image_loaded = false; 10279_via_show_img_from_buffer(img_index).then( function(ok_img_index) { 10280// trigger preload of images in buffer corresponding to img_index 10281// but, wait until all previous promises get cancelled 10282Promise.all(_via_preload_img_promise_list).then( function(values) { 10283_via_preload_img_promise_list = []; 10284var preload_promise = _via_img_buffer_start_preload( img_index, 0 ) 10285_via_preload_img_promise_list.push(preload_promise); 10286}); 10287}, function(err_img_index) { 10288console.log('_via_show_img_from_buffer() failed for file: ' + _via_image_filename_list[err_img_index]); 10289_via_current_image_loaded = false; 10290}); 10291} else { 10292// image not in buffer, so first add this image to buffer 10293_via_is_loading_current_image = true; 10294img_loading_spinbar(img_index, true); 10295_via_img_buffer_add_image(img_index).then( function(ok_img_index) { 10296_via_is_loading_current_image = false; 10297img_loading_spinbar(img_index, false); 10298_via_show_img(img_index); 10299}, function(err_img_index) { 10300_via_is_loading_current_image = false; 10301img_loading_spinbar(img_index, false); 10302show_page_404(img_index); 10303console.log('_via_img_buffer_add_image() failed for file: ' + _via_image_filename_list[err_img_index]); 10304}); 10305} 10306} 10307 10308function _via_buffer_hide_current_image() { 10309img_fn_list_ith_entry_selected(_via_image_index, false); 10310_via_clear_reg_canvas(); // clear old region shapes 10311if ( _via_current_image ) { 10312_via_current_image.classList.remove('visible'); 10313} 10314} 10315 10316function _via_show_img_from_buffer(img_index) { 10317return new Promise( function(ok_callback, err_callback) { 10318_via_buffer_hide_current_image(); 10319 10320var cimg_html_id = _via_img_buffer_get_html_id(img_index); 10321_via_current_image = document.getElementById(cimg_html_id); 10322if ( ! _via_current_image ) { 10323// the said image is not present in buffer, which could be because 10324// the image got removed from the buffer 10325err_callback(img_index); 10326return; 10327} 10328_via_current_image.classList.add('visible'); // now show the new image 10329 10330_via_image_index = img_index; 10331_via_image_id = _via_image_id_list[_via_image_index]; 10332_via_current_image_filename = _via_img_metadata[_via_image_id].filename; 10333_via_current_image_loaded = true; 10334 10335var arr_index = _via_buffer_img_index_list.indexOf(img_index); 10336_via_buffer_img_shown_timestamp[arr_index] = Date.now(); // update shown timestamp 10337 10338// update the current state of application 10339_via_click_x0 = 0; _via_click_y0 = 0; 10340_via_click_x1 = 0; _via_click_y1 = 0; 10341_via_is_user_drawing_region = false; 10342_via_is_window_resized = false; 10343_via_is_user_resizing_region = false; 10344_via_is_user_moving_region = false; 10345_via_is_user_drawing_polygon = false; 10346_via_is_region_selected = false; 10347_via_user_sel_region_id = -1; 10348_via_current_image_width = _via_current_image.naturalWidth; 10349_via_current_image_height = _via_current_image.naturalHeight; 10350 10351if ( _via_current_image_width === 0 || _via_current_image_height === 0 ) { 10352// for error image icon 10353_via_current_image_width = 640; 10354_via_current_image_height = 480; 10355} 10356 10357// set the size of canvas 10358// based on the current dimension of browser window 10359var de = document.documentElement; 10360var image_panel_width = de.clientWidth - leftsidebar.clientWidth - 20; 10361if ( leftsidebar.style.display === 'none' ) { 10362image_panel_width = de.clientWidth; 10363} 10364var image_panel_height = de.clientHeight - 2*ui_top_panel.offsetHeight; 10365 10366_via_canvas_width = _via_current_image_width; 10367_via_canvas_height = _via_current_image_height; 10368 10369if ( _via_canvas_width > image_panel_width ) { 10370// resize image to match the panel width 10371var scale_width = image_panel_width / _via_current_image.naturalWidth; 10372_via_canvas_width = image_panel_width; 10373_via_canvas_height = _via_current_image.naturalHeight * scale_width; 10374} 10375if ( _via_canvas_height > image_panel_height ) { 10376// resize further image if its height is larger than the image panel 10377var scale_height = image_panel_height / _via_canvas_height; 10378_via_canvas_height = image_panel_height; 10379_via_canvas_width = _via_canvas_width * scale_height; 10380} 10381_via_canvas_width = Math.round(_via_canvas_width); 10382_via_canvas_height = Math.round(_via_canvas_height); 10383_via_canvas_scale = _via_current_image.naturalWidth / _via_canvas_width; 10384_via_canvas_scale_without_zoom = _via_canvas_scale; 10385set_all_canvas_size(_via_canvas_width, _via_canvas_height); 10386//set_all_canvas_scale(_via_canvas_scale_without_zoom); 10387 10388// reset all regions to "not selected" state 10389toggle_all_regions_selection(false); 10390 10391// ensure that all the canvas are visible 10392set_display_area_content( VIA_DISPLAY_AREA_CONTENT_NAME.IMAGE ); 10393 10394// update img_fn_list 10395img_fn_list_ith_entry_selected(_via_image_index, true); 10396img_fn_list_scroll_to_current_file(); 10397 10398// refresh the annotations panel 10399annotation_editor_update_content(); 10400 10401_via_load_canvas_regions(); // image to canvas space transform 10402_via_redraw_reg_canvas(); 10403_via_reg_canvas.focus(); 10404 10405// Preserve zoom level 10406if (_via_is_canvas_zoomed) { 10407set_zoom( _via_canvas_zoom_level_index ); 10408} 10409ok_callback(img_index); 10410}); 10411} 10412 10413function _via_img_buffer_add_image(img_index) { 10414return new Promise( function(ok_callback, err_callback) { 10415if ( _via_buffer_img_index_list.includes(img_index) ) { 10416//console.log('_via_img_buffer_add_image(): image ' + img_index + ' already exists in buffer!') 10417ok_callback(img_index); 10418return; 10419} 10420 10421var img_id = _via_image_id_list[img_index]; 10422var img_filename = _via_img_metadata[img_id].filename; 10423if ( !_via_img_metadata.hasOwnProperty(img_id)) { 10424err_callback(img_index); 10425return; 10426} 10427 10428// check if user has given access to local file using 10429// browser's file selector 10430if ( _via_img_fileref[img_id] instanceof File ) { 10431var tmp_file_object_url = URL.createObjectURL(_via_img_fileref[img_id]); 10432var img_id = _via_image_id_list[img_index]; 10433var bimg = document.createElement('img'); 10434bimg.setAttribute('id', _via_img_buffer_get_html_id(img_index)); 10435bimg.setAttribute('src', tmp_file_object_url); 10436bimg.setAttribute('alt', 'Image loaded from base64 data of a local file selected by user.'); 10437bimg.addEventListener('error', function() { 10438URL.revokeObjectURL(tmp_file_object_url); 10439project_file_load_on_fail(img_index); 10440err_callback(img_index); 10441}); 10442bimg.addEventListener('load', function() { 10443URL.revokeObjectURL(tmp_file_object_url); 10444img_stat_set(img_index, [bimg.naturalWidth, bimg.naturalHeight]); 10445_via_img_panel.insertBefore(bimg, _via_reg_canvas); 10446project_file_load_on_success(img_index); 10447img_fn_list_ith_entry_add_css_class(img_index, 'buffered') 10448// add timestamp so that we can apply Least Recently Used (LRU) 10449// scheme to remove elements when buffer is full 10450var arr_index = _via_buffer_img_index_list.length; 10451_via_buffer_img_index_list.push(img_index); 10452_via_buffer_img_shown_timestamp[arr_index] = Date.now(); // though, not seen yet 10453ok_callback(img_index); 10454}); 10455return; 10456} 10457 10458if ( typeof(_via_img_src[img_id]) === 'undefined' || _via_img_src[img_id] === '' ) { 10459err_callback(img_index); 10460} else { 10461var img_id = _via_image_id_list[img_index]; 10462 10463var bimg = document.createElement('img'); 10464bimg.setAttribute('id', _via_img_buffer_get_html_id(img_index)); 10465_via_img_src[img_id] = _via_img_src[img_id].replace('#', '%23'); 10466bimg.setAttribute('src', _via_img_src[img_id]); 10467if ( _via_img_src[img_id].startsWith('data:image') ) { 10468bimg.setAttribute('alt', 'Source: image data in base64 format'); 10469} else { 10470bimg.setAttribute('alt', 'Source: ' + _via_img_src[img_id]); 10471} 10472 10473bimg.addEventListener('abort', function() { 10474project_file_load_on_fail(img_index); 10475err_callback(img_index); 10476}); 10477bimg.addEventListener('error', function() { 10478project_file_load_on_fail(img_index); 10479err_callback(img_index); 10480}); 10481 10482// Note: _via_current_image.{naturalWidth,naturalHeight} is only accessible after 10483// the "load" event. Therefore, all processing must happen inside this event handler. 10484bimg.addEventListener('load', function() { 10485img_stat_set(img_index, [bimg.naturalWidth, bimg.naturalHeight]); 10486_via_img_panel.insertBefore(bimg, _via_reg_canvas); 10487 10488project_file_load_on_success(img_index); 10489img_fn_list_ith_entry_add_css_class(img_index, 'buffered') 10490// add timestamp so that we can apply Least Recently Used (LRU) 10491// scheme to remove elements when buffer is full 10492var arr_index = _via_buffer_img_index_list.length; 10493_via_buffer_img_index_list.push(img_index); 10494_via_buffer_img_shown_timestamp[arr_index] = Date.now(); // though, not seen yet 10495ok_callback(img_index); 10496}, false); 10497} 10498}, false); 10499} 10500 10501function _via_img_buffer_get_html_id(img_index) { 10502return 'bim' + img_index; 10503} 10504 10505function _via_img_buffer_parse_html_id(html_id) { 10506return parseInt( html_id.substr(3) ); 10507} 10508 10509function _via_img_buffer_start_preload(img_index, preload_index) { 10510return new Promise( function(ok_callback, err_callback) { 10511_via_buffer_preload_img_index = img_index; 10512_via_img_buffer_preload_img(_via_buffer_preload_img_index, 0).then( function(ok_img_index_list) { 10513ok_callback(ok_img_index_list); 10514}); 10515}); 10516} 10517 10518function _via_img_buffer_preload_img(img_index, preload_index) { 10519return new Promise( function(ok_callback, err_callback) { 10520var preload_img_index = _via_img_buffer_get_preload_img_index(img_index, preload_index); 10521 10522if ( _via_buffer_preload_img_index !== _via_image_index ) { 10523ok_callback([]); 10524return; 10525} 10526 10527// ensure that there is sufficient buffer space left for preloading image 10528if ( _via_buffer_img_index_list.length > _via_settings.core.buffer_size ) { 10529while( _via_buffer_img_index_list.length > _via_settings.core.buffer_size ) { 10530_via_img_buffer_remove_least_useful_img(); 10531if ( _via_image_index !== _via_buffer_preload_img_index ) { 10532// current image has changed therefore, we need to cancel this preload operation 10533ok_callback([]); 10534return; 10535} 10536} 10537} 10538 10539_via_img_buffer_add_image(preload_img_index).then( function(ok_img_index) { 10540if ( _via_image_index !== _via_buffer_preload_img_index ) { 10541ok_callback( [ok_img_index] ); 10542return; 10543} 10544 10545var next_preload_index = preload_index + 1; 10546if ( next_preload_index !== VIA_IMG_PRELOAD_COUNT ) { 10547_via_img_buffer_preload_img(img_index, next_preload_index).then( function(ok_img_index_list) { 10548ok_img_index_list.push( ok_img_index ) 10549ok_callback( ok_img_index_list ); 10550}); 10551} else { 10552ok_callback( [ok_img_index] ); 10553} 10554}, function(err_img_index) { 10555// continue with preload of other images in sequence 10556var next_preload_index = preload_index + 1; 10557if ( next_preload_index !== VIA_IMG_PRELOAD_COUNT ) { 10558_via_img_buffer_preload_img(img_index, next_preload_index).then( function(ok_img_index_list) { 10559ok_callback( ok_img_index_list ); 10560}); 10561} else { 10562ok_callback([]); 10563} 10564}); 10565}); 10566} 10567 10568function _via_img_buffer_get_preload_img_index(img_index, preload_index) { 10569var preload_img_index = img_index + VIA_IMG_PRELOAD_INDICES[preload_index]; 10570if ( (preload_img_index < 0) || (preload_img_index >= _via_img_count) ) { 10571if ( preload_img_index < 0 ) { 10572preload_img_index = _via_img_count + preload_img_index; 10573} else { 10574preload_img_index = preload_img_index - _via_img_count; 10575} 10576} 10577return preload_img_index; 10578} 10579 10580// the least useful image is, one with the following properties: 10581// - preload list for current image will always get loaded, so there is no point in removing them from buffer 10582// - all the other images in buffer were seen more recently by the image 10583// - all the other images are closer (in terms of their image index) to the image currently being shown 10584function _via_img_buffer_remove_least_useful_img() { 10585var not_in_preload_list = _via_buffer_img_not_in_preload_list(); 10586var oldest_buffer_index = _via_buffer_get_oldest_in_list(not_in_preload_list); 10587 10588if ( _via_buffer_img_index_list[oldest_buffer_index] !== _via_image_index ) { 10589//console.log('removing oldest_buffer index: ' + oldest_buffer_index); 10590_via_buffer_remove(oldest_buffer_index); 10591} else { 10592var furthest_buffer_index = _via_buffer_get_buffer_furthest_from_current_img(); 10593_via_buffer_remove(furthest_buffer_index); 10594} 10595} 10596 10597function _via_buffer_remove( buffer_index ) { 10598var img_index = _via_buffer_img_index_list[buffer_index]; 10599var bimg_html_id = _via_img_buffer_get_html_id(img_index); 10600var bimg = document.getElementById(bimg_html_id); 10601if ( bimg ) { 10602_via_buffer_img_index_list.splice(buffer_index, 1); 10603_via_buffer_img_shown_timestamp.splice(buffer_index, 1); 10604_via_img_panel.removeChild(bimg); 10605 10606img_fn_list_ith_entry_remove_css_class(img_index, 'buffered') 10607} 10608} 10609 10610function _via_buffer_remove_all() { 10611var i, n; 10612n = _via_buffer_img_index_list.length; 10613for ( i = 0 ; i < n; ++i ) { 10614var img_index = _via_buffer_img_index_list[i]; 10615var bimg_html_id = _via_img_buffer_get_html_id(img_index); 10616var bimg = document.getElementById(bimg_html_id); 10617if ( bimg ) { 10618_via_img_panel.removeChild(bimg); 10619} 10620} 10621_via_buffer_img_index_list = []; 10622_via_buffer_img_shown_timestamp = []; 10623} 10624 10625function _via_buffer_get_oldest_in_list(not_in_preload_list) { 10626var i; 10627var n = not_in_preload_list.length; 10628var oldest_buffer_index = -1; 10629var oldest_buffer_timestamp = Date.now(); 10630 10631for ( i = 0; i < n; ++i ) { 10632var _via_buffer_index = not_in_preload_list[i]; 10633if ( _via_buffer_img_shown_timestamp[_via_buffer_index] < oldest_buffer_timestamp ) { 10634oldest_buffer_timestamp = _via_buffer_img_shown_timestamp[i]; 10635oldest_buffer_index = i; 10636} 10637} 10638return oldest_buffer_index; 10639} 10640 10641function _via_buffer_get_buffer_furthest_from_current_img() { 10642var now_img_index = _via_image_index; 10643var i, dist1, dist2, dist; 10644var n = _via_buffer_img_index_list.length; 10645var furthest_buffer_index = 0; 10646dist1 = Math.abs( _via_buffer_img_index_list[0] - now_img_index ); 10647dist2 = _via_img_count - dist1; // assuming the list is circular 10648var furthest_buffer_dist = Math.min(dist1, dist2); 10649 10650for ( i = 1; i < n; ++i ) { 10651dist1 = Math.abs( _via_buffer_img_index_list[i] - now_img_index ); 10652dist2 = _via_img_count - dist1; // assuming the list is circular 10653dist = Math.min(dist1, dist2); 10654// image has been seen by user at least once 10655if ( dist > furthest_buffer_dist ) { 10656furthest_buffer_dist = dist; 10657furthest_buffer_index = i; 10658} 10659} 10660return furthest_buffer_index; 10661} 10662 10663function _via_buffer_img_not_in_preload_list() { 10664var preload_list = _via_buffer_get_current_preload_list(); 10665var i; 10666var not_in_preload_list = []; 10667for ( i = 0; i < _via_buffer_img_index_list.length; ++i ) { 10668if ( ! preload_list.includes( _via_buffer_img_index_list[i] ) ) { 10669not_in_preload_list.push( i ); 10670} 10671} 10672return not_in_preload_list; 10673} 10674 10675function _via_buffer_get_current_preload_list() { 10676var i; 10677var preload_list = [_via_image_index]; 10678var img_index = _via_image_index; 10679for ( i = 0; i < VIA_IMG_PRELOAD_COUNT; ++i ) { 10680var preload_index = img_index + VIA_IMG_PRELOAD_INDICES[i]; 10681if ( preload_index < 0 ) { 10682preload_index = _via_img_count + preload_index; 10683} 10684if ( preload_index >= _via_img_count ) { 10685preload_index = preload_index - _via_img_count; 10686} 10687preload_list.push(preload_index); 10688} 10689return preload_list; 10690} 10691 10692// 10693// settings 10694// 10695function settings_panel_toggle() { 10696if ( _via_display_area_content_name === VIA_DISPLAY_AREA_CONTENT_NAME.SETTINGS ) { 10697if ( _via_display_area_content_name_prev !== '' ) { 10698set_display_area_content(_via_display_area_content_name_prev); 10699} else { 10700show_single_image_view(); 10701_via_redraw_rleg_canvas(); 10702} 10703} 10704else { 10705settings_init(); 10706set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.SETTINGS); 10707} 10708} 10709 10710function settings_init() { 10711settings_region_visualisation_update_options(); 10712settings_filepath_update_html(); 10713settings_show_current_value(); 10714} 10715 10716function settings_save() { 10717// check if default path was updated 10718var default_path_updated = false; 10719if ( document.getElementById('_via_settings.core.default_filepath').value !== _via_settings.core.default_filepath ) { 10720default_path_updated = true; 10721} 10722 10723var p = document.getElementById('settings_panel'); 10724var vl = p.getElementsByClassName('value'); 10725var n = vl.length; 10726var i; 10727for ( i = 0; i < n; ++i ) { 10728var s = vl[i].childNodes[1]; 10729var sid_parts = s.id.split('.'); 10730if ( sid_parts[0] === '_via_settings' ) { 10731var el = _via_settings; 10732var found = true; 10733var j; 10734for ( j = 1; j < sid_parts.length - 1; ++j ) { 10735if ( el.hasOwnProperty( sid_parts[j] ) ) { 10736el = el[ sid_parts[j] ]; 10737} else { 10738// unrecognized setting 10739found = false; 10740break; 10741} 10742} 10743if ( found ) { 10744var param = sid_parts[ sid_parts.length - 1 ]; 10745if ( s.value !== '' || typeof(s.value) !== 'undefined' ) { 10746el[param] = s.value; 10747} 10748} 10749} 10750} 10751 10752// non-standard settings 10753var p; 10754p = document.getElementById('settings_input_new_filepath'); 10755if ( p.value !== '' ) { 10756project_filepath_add(p.value.trim()); 10757} 10758p = document.getElementById('project_name'); 10759if ( p.value !== _via_settings.project.name ) { 10760p.value = _via_settings.project.name; 10761} 10762 10763if ( default_path_updated ) { 10764_via_file_resolve_all_to_default_filepath(); 10765_via_show_img(_via_image_index); 10766} 10767 10768show_message('Settings saved.'); 10769settings_panel_toggle(); 10770} 10771 10772function settings_show_current_value() { 10773var p = document.getElementById('settings_panel'); 10774var vl = p.getElementsByClassName('value'); 10775var n = vl.length; 10776var i; 10777for ( i = 0; i < n; ++i ) { 10778var s = vl[i].childNodes[1]; 10779var sid_parts = s.id.split('.'); 10780if ( sid_parts[0] === '_via_settings' ) { 10781var el = _via_settings; 10782var found = true; 10783var j; 10784for ( j = 1; j < sid_parts.length; ++j ) { 10785if ( el.hasOwnProperty( sid_parts[j] ) ) { 10786el = el[ sid_parts[j] ]; 10787} else { 10788// unrecognized setting 10789found = false; 10790break; 10791} 10792} 10793 10794if ( found ) { 10795s.value = el; 10796} 10797} 10798} 10799} 10800 10801function settings_region_visualisation_update_options() { 10802var region_setting_list = {'region_label': { 10803'default_option':'__via_region_id__', 10804'default_label':'Region id (1, 2, ...)', 10805'label_prefix':'Show value of region attribute: ', 10806}, 'region_color': { 10807'default_option':'__via_default_region_color__', 10808'default_label':'Default Region Colour', 10809'label_prefix':'Based on value of region attribute: ', 10810}}; 10811 10812for ( var setting in region_setting_list ) { 10813var select = document.getElementById('_via_settings.ui.image.' + setting); 10814select.innerHTML = ''; 10815var default_option = document.createElement('option'); 10816default_option.setAttribute('value', region_setting_list[setting]['default_option']); 10817if ( _via_settings.ui.image[setting] === region_setting_list[setting]['default_option'] ) { 10818default_option.setAttribute('selected', 'selected'); 10819} 10820default_option.innerHTML = region_setting_list[setting]['default_label']; 10821select.appendChild(default_option); 10822 10823// options: add region attributes 10824var rattr; 10825for ( rattr in _via_attributes['region'] ) { 10826var o = document.createElement('option'); 10827o.setAttribute('value', rattr); 10828o.innerHTML = region_setting_list[setting]['label_prefix'] + rattr; 10829if ( _via_settings.ui.image.region_label === rattr ) { 10830o.setAttribute('selected', 'selected'); 10831} 10832select.appendChild(o); 10833} 10834} 10835} 10836 10837function settings_filepath_update_html() { 10838var p = document.getElementById('_via_settings.core.filepath'); 10839p.innerHTML = ''; 10840var i, path, order; 10841for ( path in _via_settings.core.filepath ) { 10842order = _via_settings.core.filepath[path] 10843if ( order !== 0 ) { 10844var li = document.createElement('li'); 10845li.innerHTML = path + '<span class="text_button" title="Delete image path" onclick="project_filepath_del(\"' + path + '\"); settings_filepath_update_html();">×</span>'; 10846p.appendChild(li); 10847} 10848} 10849} 10850 10851// 10852// find location of file 10853// 10854 10855function _via_file_resolve_all_to_default_filepath() { 10856var img_id; 10857for ( img_id in _via_img_metadata ) { 10858if ( _via_img_metadata.hasOwnProperty(img_id) ) { 10859_via_file_resolve_file_to_default_filepath(img_id); 10860} 10861} 10862} 10863 10864function _via_file_resolve_file_to_default_filepath(img_id) { 10865if ( _via_img_metadata.hasOwnProperty(img_id) ) { 10866if ( typeof(_via_img_fileref[img_id]) === 'undefined' || ! _via_img_fileref[img_id] instanceof File ) { 10867if ( is_url( _via_img_metadata[img_id].filename ) ) { 10868_via_img_src[img_id] = _via_img_metadata[img_id].filename; 10869} else { 10870_via_img_src[img_id] = _via_settings.core.default_filepath + _via_img_metadata[img_id].filename; 10871} 10872} 10873} 10874} 10875 10876function _via_file_resolve_all() { 10877return new Promise( function(ok_callback, err_callback) { 10878var all_promises = []; 10879 10880var search_path_list = _via_file_get_search_path_list(); 10881var i, img_id; 10882for ( i = 0; i < _via_img_count; ++i ) { 10883img_id = _via_image_id_list[i]; 10884if ( typeof(_via_img_src[img_id]) === 'undefined' || _via_img_src[img_id] === '' ) { 10885var p = _via_file_resolve(i, search_path_list); 10886all_promises.push(p); 10887} 10888} 10889 10890Promise.all( all_promises ).then( function(ok_file_index_list) { 10891console.log(ok_file_index_list); 10892ok_callback(); 10893//project_file_load_on_success(ok_file_index); 10894}, function(err_file_index_list) { 10895console.log(err_file_index_list); 10896err_callback(); 10897//project_file_load_on_fail(err_file_index); 10898}); 10899 10900}); 10901} 10902 10903function _via_file_get_search_path_list() { 10904var search_path_list = []; 10905var path; 10906for ( path in _via_settings.core.filepath ) { 10907if ( _via_settings.core.filepath[path] !== 0 ) { 10908search_path_list.push(path); 10909} 10910} 10911return search_path_list; 10912} 10913 10914function _via_file_resolve(file_index, search_path_list) { 10915return new Promise( function(ok_callback, err_callback) { 10916var path_index = 0; 10917var p = _via_file_resolve_check_path(file_index, path_index, search_path_list).then(function(ok) { 10918ok_callback(ok); 10919}, function(err) { 10920err_callback(err); 10921}); 10922}, false); 10923} 10924 10925function _via_file_resolve_check_path(file_index, path_index, search_path_list) { 10926return new Promise( function(ok_callback, err_callback) { 10927var img_id = _via_image_id_list[file_index]; 10928var img = new Image(0,0); 10929 10930var img_path = search_path_list[path_index] + _via_img_metadata[img_id].filename; 10931if ( is_url( _via_img_metadata[img_id].filename ) ) { 10932if ( search_path_list[path_index] !== '' ) { 10933// we search for the the image filename pointed by URL in local search paths 10934img_path = search_path_list[path_index] + get_filename_from_url( _via_img_metadata[img_id].filename ); 10935} 10936} 10937 10938img.setAttribute('src', img_path); 10939 10940img.addEventListener('load', function() { 10941_via_img_src[img_id] = img_path; 10942ok_callback(file_index); 10943}, false); 10944img.addEventListener('abort', function() { 10945err_callback(file_index); 10946}); 10947img.addEventListener('error', function() { 10948var new_path_index = path_index + 1; 10949if ( new_path_index < search_path_list.length ) { 10950_via_file_resolve_check_path(file_index, new_path_index, search_path_list).then( function(ok) { 10951ok_callback(file_index); 10952}, function(err) { 10953err_callback(file_index); 10954}); 10955} else { 10956err_callback(file_index); 10957} 10958}, false); 10959}, false); 10960} 10961 10962// 10963// page 404 (file not found) 10964// 10965function show_page_404(img_index) { 10966_via_buffer_hide_current_image(); 10967 10968set_display_area_content(VIA_DISPLAY_AREA_CONTENT_NAME.PAGE_404); 10969 10970_via_image_index = img_index; 10971_via_image_id = _via_image_id_list[_via_image_index]; 10972_via_current_image_loaded = false; 10973img_fn_list_ith_entry_selected(_via_image_index, true); 10974 10975document.getElementById('page_404_filename').innerHTML = '[' + (_via_image_index+1) + ']' + _via_img_metadata[_via_image_id].filename; 10976} 10977 10978 10979// 10980// utils 10981// 10982 10983function is_url( s ) { 10984// @todo: ensure that this is sufficient to capture all image url 10985if ( s.startsWith('http://') || s.startsWith('https://') || s.startsWith('www.') ) { 10986return true; 10987} else { 10988return false; 10989} 10990} 10991 10992function get_filename_from_url( url ) { 10993return url.substring( url.lastIndexOf('/') + 1 ); 10994} 10995 10996function fixfloat(x) { 10997return parseFloat( x.toFixed(VIA_FLOAT_PRECISION) ); 10998} 10999 11000function shape_attribute_fixfloat(sa) { 11001for ( var attr in sa ) { 11002switch(attr) { 11003case 'x': 11004case 'y': 11005case 'width': 11006case 'height': 11007case 'r': 11008case 'rx': 11009case 'ry': 11010sa[attr] = fixfloat( sa[attr] ); 11011break; 11012case 'all_points_x': 11013case 'all_points_y': 11014for ( var i in sa[attr] ) { 11015sa[attr][i] = fixfloat( sa[attr][i] ); 11016} 11017} 11018} 11019} 11020 11021// start with the array having smallest number of elements 11022// check the remaining arrays if they all contain the elements of this shortest array 11023function array_intersect( array_list ) { 11024if ( array_list.length === 0 ) { 11025return []; 11026} 11027if ( array_list.length === 1 ) { 11028return array_list[0]; 11029} 11030 11031var shortest_array = array_list[0]; 11032var shortest_array_index = 0; 11033var i; 11034for ( i = 1; i < array_list.length; ++i ) { 11035if ( array_list[i].length < shortest_array.length ) { 11036shortest_array = array_list[i]; 11037shortest_array_index = i; 11038} 11039} 11040 11041var intersect = []; 11042var element_count = {}; 11043 11044var array_index_i; 11045for ( i = 0; i < array_list.length; ++i ) { 11046if ( i === 0 ) { 11047// in the first iteration, process the shortest element array 11048array_index_i = shortest_array_index; 11049} else { 11050array_index_i = i; 11051} 11052 11053var j; 11054for ( j = 0; j < array_list[array_index_i].length; ++j ) { 11055if ( element_count[ array_list[array_index_i][j] ] === (i-1) ) { 11056if ( i === array_list.length - 1 ) { 11057intersect.push( array_list[array_index_i][j] ); 11058element_count[ array_list[array_index_i][j] ] = 0; 11059} else { 11060element_count[ array_list[array_index_i][j] ] = i; 11061} 11062} else { 11063element_count[ array_list[array_index_i][j] ] = 0; 11064} 11065} 11066} 11067return intersect; 11068} 11069 11070function generate_img_index_list(input) { 11071var all_img_index_list = []; 11072 11073// condition: count format a,b 11074var count_format_img_index_list = []; 11075if ( input.prev_next_count.value !== '' ) { 11076var prev_next_split = input.prev_next_count.value.split(','); 11077if ( prev_next_split.length === 2 ) { 11078var prev = parseInt( prev_next_split[0] ); 11079var next = parseInt( prev_next_split[1] ); 11080var i; 11081for ( i = (_via_image_index - prev); i <= (_via_image_index + next); i++ ) { 11082count_format_img_index_list.push(i); 11083} 11084} 11085} 11086if ( count_format_img_index_list.length !== 0 ) { 11087all_img_index_list.push(count_format_img_index_list); 11088} 11089 11090//condition: image index list expression 11091var expr_img_index_list = []; 11092if ( input.img_index_list.value !== '' ) { 11093var img_index_expr = input.img_index_list.value.split(','); 11094if ( img_index_expr.length !== 0 ) { 11095var i; 11096for ( i = 0; i < img_index_expr.length; ++i ) { 11097if ( img_index_expr[i].includes('-') ) { 11098var ab = img_index_expr[i].split('-'); 11099var a = parseInt( ab[0] ) - 1; // 0 based indexing 11100var b = parseInt( ab[1] ) - 1; 11101var j; 11102for ( j = a; j <= b; ++j ) { 11103expr_img_index_list.push(j); 11104} 11105} else { 11106expr_img_index_list.push( parseInt(img_index_expr[i]) - 1 ); 11107} 11108} 11109} 11110} 11111if ( expr_img_index_list.length !== 0 ) { 11112all_img_index_list.push(expr_img_index_list); 11113} 11114 11115 11116// condition: regular expression 11117var regex_img_index_list = []; 11118if ( input.regex.value !== '' ) { 11119var regex = input.regex.value; 11120for ( var i=0; i < _via_image_filename_list.length; ++i ) { 11121var filename = _via_image_filename_list[i]; 11122if ( filename.match(regex) !== null ) { 11123regex_img_index_list.push(i); 11124} 11125} 11126} 11127if ( regex_img_index_list.length !== 0 ) { 11128all_img_index_list.push(regex_img_index_list); 11129} 11130 11131var intersect = array_intersect(all_img_index_list); 11132return intersect; 11133} 11134 11135if ( ! _via_is_debug_mode ) { 11136// warn user of possible loss of data 11137window.onbeforeunload = function (e) { 11138e = e || window.event; 11139 11140// For IE and Firefox prior to version 4 11141if (e) { 11142e.returnValue = 'Did you save your data?'; 11143} 11144 11145// For Safari 11146return 'Did you save your data?'; 11147}; 11148} 11149 11150// 11151// keep a record of image statistics (e.g. width, height, ...) 11152// 11153function img_stat_set(img_index, stat) { 11154if ( stat.length ) { 11155_via_img_stat[img_index] = stat; 11156} else { 11157delete _via_img_stat[img_index]; 11158} 11159} 11160 11161function img_stat_set_all() { 11162return new Promise( function(ok_callback, err_callback) { 11163var promise_list = []; 11164var img_id; 11165for ( var img_index in _via_image_id_list ) { 11166if ( ! _via_img_stat.hasOwnProperty(img_index) ) { 11167img_id = _via_image_id_list[img_index]; 11168if ( _via_img_metadata[img_id].file_attributes.hasOwnProperty('width') && 11169_via_img_metadata[img_id].file_attributes.hasOwnProperty('height') 11170) { 11171_via_img_stat[img_index] = [_via_img_metadata[img_id].file_attributes['width'], 11172_via_img_metadata[img_id].file_attributes['height'], 11173]; 11174} else { 11175promise_list.push( img_stat_get(img_index) ); 11176} 11177} 11178} 11179if ( promise_list.length ) { 11180Promise.all(promise_list).then( function(ok) { 11181ok_callback(); 11182}.bind(this), function(err) { 11183console.warn('Failed to read statistics of all images!'); 11184err_callback(); 11185}); 11186} else { 11187ok_callback(); 11188} 11189}.bind(this)); 11190} 11191 11192function img_stat_get(img_index) { 11193return new Promise( function(ok_callback, err_callback) { 11194var img_id = _via_image_id_list[img_index]; 11195var tmp_img = document.createElement('img'); 11196var tmp_file_object_url = null; 11197tmp_img.addEventListener('load', function() { 11198_via_img_stat[img_index] = [tmp_img.naturalWidth, tmp_img.naturalHeight]; 11199if ( tmp_file_object_url !== null ) { 11200URL.revokeObjectURL(tmp_file_object_url); 11201} 11202ok_callback(); 11203}.bind(this)); 11204tmp_img.addEventListener('error', function() { 11205_via_img_stat[img_index] = [-1, -1]; 11206if ( tmp_file_object_url !== null ) { 11207URL.revokeObjectURL(tmp_file_object_url); 11208} 11209ok_callback(); 11210}.bind(this)); 11211 11212if ( _via_img_fileref[img_id] instanceof File ) { 11213tmp_file_object_url = URL.createObjectURL(_via_img_fileref[img_id]); 11214tmp_img.src = tmp_file_object_url; 11215} else { 11216tmp_img.src = _via_img_src[img_id]; 11217} 11218}.bind(this)); 11219} 11220 11221 11222// pts = [x0,y0,x1,y1,....] 11223function polygon_to_bbox(pts) { 11224var xmin = +Infinity; 11225var xmax = -Infinity; 11226var ymin = +Infinity; 11227var ymax = -Infinity; 11228for ( var i = 0; i < pts.length; i = i + 2 ) { 11229if ( pts[i] > xmax ) { 11230xmax = pts[i]; 11231} 11232if ( pts[i] < xmin ) { 11233xmin = pts[i]; 11234} 11235if ( pts[i+1] > ymax ) { 11236ymax = pts[i+1]; 11237} 11238if ( pts[i+1] < ymin ) { 11239ymin = pts[i+1]; 11240} 11241} 11242return [xmin, ymin, xmax-xmin, ymax-ymin]; 11243} 11244</script> 11245<!-- END: Contents of file: via.js--> 11246</body> 11247</html> 11248